C++ 在多线程C++;11计划?

C++ 在多线程C++;11计划?,c++,multithreading,exception,c++11,c++-faq,C++,Multithreading,Exception,C++11,C++ Faq,如果一个C++11程序运行两个线程,其中一个线程抛出未处理的异常,会发生什么?整个程序会死于非命吗?抛出异常的线程是否会单独死亡(如果是,在这种情况下我可以获得异常)?完全是别的吗?什么都没有真正改变。n3290中的措辞是: 如果未找到匹配的处理程序,则调用函数std::terminate() terminate的行为可以通过set\u terminate进行自定义,但是: 所需行为:terminate\u处理程序应在不返回调用方的情况下终止程序的执行 因此,在这种情况下,程序将退出,其他线程将

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

什么都没有真正改变。n3290中的措辞是:

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

terminate
的行为可以通过
set\u terminate
进行自定义,但是:

所需行为:
terminate\u处理程序
应在不返回调用方的情况下终止程序的执行


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

由于对异常传播似乎有合理的兴趣,并且这至少与问题有点相关,因此我的建议是:
std::thread
被视为构建更高级别抽象的不安全原语。它们在异常方面具有双重风险:如果在我们刚刚启动的线程中发生异常,一切都会崩溃,正如我们所展示的。但是,如果启动
std::thread
的线程中发生异常,我们可能会遇到麻烦,因为
std::thread
的析构函数要求将
*此
连接或分离(或者等效地,不是线程)。违反这些要求将导致。。。调用
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
当然,有些人可能会争辩说,如果我们简单地
分离
我们启动的每个线程,我们在第二点上是安全的。问题是在某些情况下,
join
是最明智的做法。例如,快速排序的“幼稚”并行化需要等待子任务结束。在这些情况下,
join
充当同步原语(rendez-vous)


幸运的是,我提到的那些更高层次的抽象确实存在,并且与标准库一起提供。它们是
std::async
std::future
以及
std::packaged_task
std::promise
std::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();

非常肯定线程会死,你不能“照顾”它而不抓住线程内的线程…但我认为其他线程将继续。我很想听到一个权威性的答案。@sje397:我当然不会打赌这个过程会继续下去。我想知道如果使用
exception\u ptr
我们可以希望异常能够跨线程传播,这会很好。似乎我错了。很好的问题。@Matthieu:在跨线程调用期间封送到另一个线程的异常不会被视为“未处理”,IMO.
std::exception_ptr
允许将异常从一个线程迁移到另一个线程,这种传播是否自动进行,以便在调用线程中引发异常?(可以说,这可能很难)@Kerrek No你绝对无法捕捉到“线程或起源”之外的异常。异常捕获取决于堆栈展开,堆栈基本上是特定于线程的。在C++03中(如果线程超出标准),使用pthreads。主线程中未捕获的异常会终止应用程序(正常情况下)。但是子线程中的异常只会杀死该线程。我很惊讶,这个行为并不是新标准所说的应该实现的。@Branko:对于C++0x futures,异常肯定应该随结果一起传输。这意味着必须首先在工作线程中进行解绕(因为工作线程甚至可能退出),然后传输异常。@Kerrek:阅读第30.6节,该节讨论“未来”并描述结果(包括异常)如何传播。+1绝对同意将
std::thread
视为不安全的原语。
// 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