提问人:R. Martinho Fernandes 提问时间:9/1/2011 最后编辑:sbiR. Martinho Fernandes 更新时间:12/18/2012 访问量:17282
当多线程 C++11 程序中的异常未处理时会发生什么?
What happens when an exception goes unhandled in a multithreaded C++11 program?
问:
如果我有一个运行两个线程的 C++11 程序,其中一个线程引发未经处理的异常,会发生什么情况?整个程序会死得很惨吗?抛出异常的线程是否会单独死亡(如果是这样,在这种情况下我可以获取异常吗)?完全是别的什么?
答:
一切都没有真正改变。n3290 中的措辞是:
如果未找到匹配的处理程序,则调用该函数
std::terminate()
可以使用 自定义行为,但是:terminate
set_terminate
所需行为:A 应终止程序的执行,而不返回调用方。
terminate_handler
因此,在这种情况下程序会退出,其他线程无法继续运行。
评论
std::exception_ptr
允许将异常从一个线程迁移到另一个线程,这种传播是否自动进行,以便在调用线程中抛出异常?(可以说,这可能很困难)
由于异常传播似乎有合法的兴趣,并且这至少与问题略有关系,因此我的建议是:被视为构建更高级别抽象的不安全原语。它们在异常方面具有双重风险:如果我们刚刚启动的线程内发生异常,一切都会爆炸,正如我们所展示的那样。但是,如果在启动的线程中发生异常,我们可能会遇到麻烦,因为析构函数要求连接或分离(或等效地,不是线程)。违反这些要求会导致......调用 !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::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();
事实上,与其调用调用的线程,不如将责任传递给另一个线程: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
评论
std::thread
评论
exception_ptr