对于一些多线程代码,我希望捕获所有异常并将它们传递给单个异常处理线程。以下是消息传递框架:
#include <exception>
struct message
{
virtual ~message() = default;
virtual void act() = 0;
};
struct exception_message : message
{
std::exception_ptr ep;
virtual void act()
{
std::rethrow_exception(ep);
}
// ...
};
这是一个用例:
try
{
// ...
}
catch (...)
{
exception_message em { std::current_exception(); }
handler_thread.post_message(em);
}
处理程序线程处理它的所有消息并调用act()
,它可以安装自己的try/catch块来处理所有发布的异常。
现在我想知道如果我把这个消息的副本发送给多个接收者会发生什么。一般来说,messages可能有任何数量的收件人,所以我不想对exception propagation消息。exception_ptr
被记录为"共享所有权"智能指针,而rethrow_exception
"不引入数据竞赛"。
所以我的问题是:通过将活动异常存储在exception_ptr
,copy调用指针,并多次调用rethrow_exception
?
根据我对标准的理解,它是合法的。然而,我要注意的是,rethrow不会复制异常,因此,如果您修改共享异常对象并同时从其他线程访问它,共享异常对象本身就会提交给数据竞赛。如果异常是只读的(一旦抛出),那么您应该不会有任何问题。
关于存储时间:
15.1引发异常〔except.sthrow〕
4异常对象的内存以未指定的方式分配,3.7.4.1中指出的除外。如果某个处理程序通过重新引发退出,则控制权将传递给同一异常的另一个处理程序。在异常的最后一个剩余活动处理程序通过除重新抛出之外的任何方式退出后,或者引用异常对象的最后一种类型为
std::exception_ptr
(18.8.5)的对象为销毁,以较晚者为准。在前一种情况下,销毁发生在处理程序退出时,即在销毁处理程序中异常声明中声明的对象(如果有的话)之后。在后一种情况下,破坏发生在std::exception_ptr
的析构函数返回之前。
关于数据竞赛:
18.8.5异常传播[传播]
7为了确定是否存在数据竞争,对
exception_ptr
对象的操作只能访问和修改exception_ptr
对象本身,而不能访问和修改它们引用的异常。对引用同一异常对象的exception_ptr
对象使用rethrow_exception
不应引入数据竞争。[注意:如果rethrow_exception
重新抛出相同的异常对象(而不是副本),则对该重新抛出的异常对象的并发访问可能会引入数据竞争。引用特定异常的exception_ptr
对象数量的变化不会引入数据种族--尾注]
关于rethrow
:
[[noreturn]] void rethrow_exception(exception_ptr p);
9要求:
p
不应为空指针。10抛出:p所指的异常对象。