在多线程c++ 11程序中,当异常未处理时会发生什么

What happens when an exception goes unhandled in a multithreaded C++11 program?

本文关键字:未处理 什么 异常 c++ 多线程 程序      更新时间:2023-10-16

如果我有一个运行两个线程的c++ 11程序,其中一个抛出了一个未处理的异常,会发生什么?整个项目会不会死得很惨?抛出异常的线程会单独死亡吗(如果是的话,我可以在这种情况下获得异常吗)?完全不同的东西?

一切都没有改变。n3290中的措辞是:

如果没有找到匹配的处理程序,则调用函数std::terminate()

terminate的行为可以用set_terminate来定制,但是:

所需行为: terminate_handler应终止程序的执行而不返回调用者。

在这种情况下程序退出,其他线程不能继续运行

由于似乎对异常传播有合法的兴趣,并且这与问题稍微相关,因此我的建议是:将std::thread视为构建例如更高级别抽象的不安全原语。它们在异常方面具有双重风险:如果在我们刚刚启动的线程中出现异常,那么一切都会爆炸,正如我们所展示的那样。但是,如果在启动std::thread的线程中出现异常,我们可能会遇到麻烦,因为std::thread的析构函数要求*this要么加入,要么分离(或者等价地,不是线程)。违反这些要求会导致……调用std::terminate !

std::thread危险的代码图:

auto run = []
{
    // if an exception escapes here std::terminate is called
};
std::thread thread(run);
// notice that we do not detach the thread
// if an exception escapes here std::terminate is called
thread.join();
// end of scope
当然,有些人可能会争辩说,如果我们简单地对我们启动的每个线程进行detach,我们在第二个点上是安全的。问题是,在某些情况下,join是最明智的做法。例如,快速排序的"幼稚"并行化需要等到子任务结束。在这些情况下,join充当同步原语(一个会合点)。

幸运的是,我提到的那些更高层次的抽象确实存在,并且随标准库而来。它们是std::async, std::future以及std::packaged_task, std::promisestd::exception_ptr。上面的等价的异常安全版本:

auto run = []() -> T // T may be void as above
{
    // may throw
    return /* some T */;
};
auto launched = std::async(run);
// launched has type std::future<T>
// may throw here; nothing bad happens
// expression has type T and may throw
// will throw whatever was originally thrown in run
launched.get();

实际上,在调用async的线程中不调用get可以将buck传递给另一个线程:

// only one call to get allowed per std::future<T> so
// this replaces the previous call to get
auto handle = [](std::future<T> future)
{
    // get either the value returned by run
    // or the exception it threw
    future.get();
};
// std::future is move-only
std::async(handle, std::move(launched));
// we didn't name and use the return of std::async
// because we don't have to