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

R. *_*des 59 c++ multithreading exception c++-faq c++11

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

Ben*_*igt 50

什么都没有改变.n3290中的措辞是:

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

行为terminate可以自定义set_terminate,但是:

必需的行为:A terminate_handler应终止程序的执行而不返回调用者.

所以程序在这种情况下退出,其他线程无法继续运行.

  • @Kerrek不,你绝对不能在其"线程或原点"之外捕获异常.异常捕获取决于堆栈展开,而堆栈基本上是特定于线程的. (3认同)
  • 在 C++03 中(线程在标准之外)与 pthreads。未捕获的主线程中的异常会终止应用程序(正常情况下)。但是子线程中的异常只会杀死该线程。我很惊讶这种行为并不是新标准所说的应该实施的。 (2认同)

Luc*_*ton 28

由于似乎对异常传播有合理的兴趣,这与问题略有关联,这里是我的建议: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
Run Code Online (Sandbox Code Playgroud)

当然,有些人可能会争辩说,如果我们简单地detach编辑我们发布的每一个帖子,那么我们在第二点就是安全的.问题在于,在某些情况下,这join是最明智的做法.例如,快速排序的"天真"并行化需要等到子任务结束.在那些情况下join充当同步原语(rendez-vous).

对我们来说幸运的是,我提到的那些更高级别的抽象确实存在并且随标准库一起提供.他们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();
Run Code Online (Sandbox Code Playgroud)

事实上,而不是调用调用get的线程,async而不是将降压传递给另一个线程:

// 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
Run Code Online (Sandbox Code Playgroud)

  • +1绝对同意将`std :: thread`视为不安全的原语. (5认同)