C++ необработанное исключение в рабочем потоке

Необработанное исключение ведет себя по-разному для основного потока и другого 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 & Jive Dadson, я должен перепутать некоторые понятия: 1) обработка исключений / ошибок; 2) утверждение времени выполнения 3) ошибка сегмента, 2 и 3 аналогичны, они являются неисправимыми ошибками UN, единственным вариантом является немедленное прерывание, они также удобны для отслеживания в отладчике, поскольку разматывание стека не задействовано. они вообще не должны реализовываться с использованием концепции исключений. исключение должно быть перехвачено всегда, пусть uncaught исключения, оставляя main() не рекомендуется использовать.

2 ответа

Зачем? Так оно и есть. Начиная с 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";
            }
        }
    }
}

Вы должны перехватить исключение в потоке, где оно возникает. Обработчик по умолчанию вызовет terminate() где бы он ни находился, разматывать или нет в зависимости от реализации.

Другие вопросы по тегам