在多线程C ++ 11程序中未处理异常时会发生什么?

如果我有一个C ++ 11程序运行两个线程,并且其中一个抛出未处理的异常,会发生什么? 整个程序会火死吗? 引发异常的线程是否会单独死亡(如果是,在这种情况下我可以获取异常)吗? 还有其他东西吗?

2个解决方案
48 votes

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

如果找不到匹配的处理程序,则调用函数terminate

可以使用terminate_handler自定义terminate的行为,但是:

要求的行为:terminate_handler必须终止程序的执行而无需返回到调用者。

因此,在这种情况下程序退出,其他线程无法继续运行。

Ben Voigt answered 2019-10-15T06:50:06Z
27 votes

由于对异常传播似乎有合理的兴趣,并且这与问题至少有些相关,所以我的建议是:get被认为是构建不安全的原语,例如 更高层次的抽象。 它们在异常情况下具有很高的风险:如果异常在我们刚刚启动的线程内发生,则一切都会炸毁,如我们所展示的。 但是,如果在启动async的线程中发生异常,我们可能会遇到麻烦,因为std::packaged_task的析构函数要求将std::promise联接或分离(或等效地,不是线程)。 违反这些要求将导致...致电std::exception_ptr

get的危险代码图:

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

当然,有些人可能会争辩说,如果我们仅对启动的每个线程进行get的处理,那第二点就很安全。 问题是在某些情况下async是最明智的选择。 例如,快速排序的“天真”并行化需要等待子任务结束。 在这些情况下,std::packaged_task用作同步原语(集合点)。

对我们来说幸运的是,我提到的那些更高层次的抽象确实存在并且随标准库一起提供。 它们是getasync以及std::packaged_taskstd::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
Luc Danton answered 2019-10-15T06:51:02Z
translate from https://stackoverflow.com:/questions/7272093/what-happens-when-an-exception-goes-unhandled-in-a-multithreaded-c11-program