У меня есть программа, которая создает, который использует std::thread
объекты для выполнения работы одновременно. Я вызываю программу из скрипта bash и хочу остановить скрипт, если программа не завершается с EXIT_SUCCESS
, Я столкнулся с довольно неинтуитивным поведением в следующей ситуации: один из потоков выдает исключение (таким образом вызывая std::terminate
), что приводит к завершению программы. Тем не менее, код возврата программы EXIT_SUCCESS
(вместо некоторого кода ошибки, который я бы ожидал). Это почему?
Я знаю что используя std::thread
это не умная идея во многих случаях, и я планирую перейти к std::async
(или тому подобное), но на данный момент я заинтересован в быстром решении этого.
Ну, считай меня глупым. Программа корректно возвращает код ошибки, но, как я передал вывод (он пишет много журнала) в tee
код возврата хранится в $?
вероятно, один из tee
, который выходит без сбоев.
PIPESTATUS
Теперь, чтобы получить правильный код выхода.
Как отметил Ричард Криттен в комментарии std::terminate()
звонки std::abort()
, но это не все.
C ++ предлагает довольно много механизмов для контроля таких ситуаций. Я могу предложить следующее:
Зарегистрируйте свой собственный обработчик для вызовов std::terminate()
с использованием std::set_terminate()
:
#include <iostream>
#include <cstdlib>
#include <exception>
int main()
{
std::set_terminate
( []()
{
std::cout << "Unhandled exception\n";
std::exit(EXIT_FAILURE);
}
);
throw 1;
}
призвание std::exit()
вызывает нормальное завершение программы с некоторыми шагами очистки.
Другой альтернативой будет регистрация SIGABORT
обработчик и выйдите из программы с желаемым кодом выхода. Но в этом случае очистка ресурсов не производится.
C ++ 11 имеет exception_ptr
тип, который позволяет транспортировать исключения между потоками. Так что в случае, если вы хотите обрабатывать исключения, вы можете рассмотреть следующий подход.
#include <iostream>
#include<thread>
#include<exception>
#include<stdexcept>
static std::exception_ptr eptr = nullptr;
void foo()
{
try
{
....
throw std::runtime_error("Bla bla"); // put your exception instead of runtime_error
}
catch(...)
{
eptr = std::current_exception();
}
}
int main(int argc, char **argv)
{
std::thread t(foo);
t.join();
if (eptr)
{
try
{
std::rethrow_exception(eptr);
}
catch(const std::exception &ex)
{
std::cerr << "Thread exited: " << ex.what() << "\n";
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
Этот метод гарантирует, что программа выйдет со статусом EXIT_FAILURE
если поток выдает исключение.