Необработанное исключение ведет себя по-разному для основного потока и другого std :: thread.
вот тестовая программа
#include <thread>
class XXX{
public:
XXX(){std::fprintf(stderr, "XXX ctor\n");}
~XXX(){std::fprintf(stderr, "XXX dtor\n");}
};
void mytest(int i)
{
XXX xtemp;
throw std::runtime_error("Hello, world!");
}
int main(int argc, char *argv[])
{
if(argc == 1) {
mytest(0);
}else{
std::thread th([&]{mytest(0);});
th.join();
}
}
код выше (C ++ 11), скомпилированный GCC 5.4
бегать без аргументов
XXX ctor
terminate called after throwing an instance of 'std::runtime_error'
what(): Hello, world!
Aborted (core dumped)
запустить 1 арг:
XXX ctor
XXX dtor
terminate called after throwing an instance of 'std::runtime_error'
what(): Hello, world!
Aborted (core dumped)
Таким образом, разматывание стека выполняется в рабочем потоке, а не в основном потоке, ПОЧЕМУ?
Я спрашиваю, потому что я хотел бы, чтобы дамп ядра давал полезную информацию о трассировке стека в обоих случаях (для неперехваченного исключения).
Заранее спасибо!!!
Дальнейшие испытания показывают, что добавить noexcept Ключевое слово в функцию потока Тело mytest () может частично решить мою проблему, потому что размотка не удастся, но это не очень хорошее решение, потому что разматывание все равно будет частично происходить, если mytest () вызывает другую функцию без гарантии noexcept и фактически выдает необработанное исключение.
Обновление: благодаря всем поставщикам комментариев, теперь я понимаю, что исключение C ++ не является дружественным к обратному следу, и GCC, как реализация C ++, имеет свободу выбора не раскручивать, когда неперехваченное исключение выдается из основного потока, и раскручивать, когда из рабочего потока.
Обновление: отдельное спасибо Sid S & Джайв Дадсон, я должен перепутать некоторые понятия: 1) обработка исключений / ошибок; 2) утверждение времени выполнения 3) ошибка сегмента, 2&3 схожи, они неустранимые ошибки, немедленный прерывание — единственный выбор, они также дружественны к обратному следу в отладчике, потому что разматывание стека не задействовано. они вообще не должны реализовываться с использованием концепции исключений. исключение должно быть перехвачено всегда, пусть uncaught исключения, оставляя main () не рекомендуется использовать.
Вы должны перехватить исключение в потоке, где оно возникает. Обработчик по умолчанию вызовет terminate()
где бы он ни находился, разматывать или нет в зависимости от реализации.
Зачем? Так оно и есть. Начиная с c ++ 11, есть некоторая поддержка для работы с исключениями, генерируемыми в потоках, отличных от main, но вам нужно будет обрабатывать потоки, чтобы перехватывать исключения и перебрасывать их. Вот как.
#include <thread>
#include <iostream>
class XXX {
public:
XXX() { std::fprintf(stderr, "XXX ctor\n"); }
~XXX() { std::fprintf(stderr, "XXX dtor\n"); }
};
void mytest(int i)
{
XXX xtemp;
throw std::runtime_error("Hello, world!");
}
int main(int argc, char *argv[])
{
std::exception_ptr exception_ptr = nullptr;
if (argc == 1) {
mytest(0);
}
else {
std::thread th([&exception_ptr]() {
try {
mytest(0);
}
catch (...) {
exception_ptr = std::current_exception();
}
});
th.join();
if (exception_ptr) {
try {
std::rethrow_exception(exception_ptr);
}
catch (const std::exception &ex)
{
std::cerr << "Thread exited with exception: " << ex.what() << "\n";
}
}
}
}