对于某些多线程代码,我想捕获所有异常并将它们传递给单个异常处理线程。这是消息传递框架:
#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块来处理所有发布的异常。
现在我想知道如果我将此消息发送到多个接收器会发生什么。通常,消息可能有任意数量的收件人,因此我不想对异常传播消息设置任意限制。 exception_ptr
被记录为“共享所有权”智能指针,而rethrow_exception
“不会引入数据竞争”。
所以我的问题:通过将活动异常存储在exception_ptr
中,复制指针并多次调用rethrow_exception
来复制活动异常是否合法?
答案 0 :(得分:5)
根据我对标准的理解,这是合法的。但是我会注意到重新抛出不会重复异常,因此如果你修改它并从其他线程访问它,共享异常对象本身就会被提交给数据竞争。如果异常是只读的(一旦抛出),那么你应该没有任何问题。
关于存储期限:
15.1抛出异常[except.throw]
4 除3.7.4.1中所述外,异常对象的内存以未指定的方式分配。如果处理程序通过重新抛出退出,则控制将传递给另一个处理程序以获取相同的异常。异常对象在异常的最后剩余活动处理程序通过除了重新抛出之外的任何方式退出之后被销毁,或者引用异常对象的类型
std::exception_ptr
(18.8.5)的最后一个对象是 被摧毁,以较晚者为准。在前一种情况下,当处理程序退出时,在销毁处理程序中的异常声明中声明的对象(如果有)之后立即发生销毁。在后一种情况下,破坏发生在std::exception_ptr
的析构函数返回之前。
关于数据竞赛:
18.8.5异常传播[传播]
7 为了确定是否存在数据争用,
exception_ptr
对象上的操作只能访问和修改exception_ptr
个对象本身,而不是它们引用的异常。在引用同一异常对象的rethrow_exception
个对象上使用exception_ptr
不会引入数据竞争。 [注意:如果rethrow_exception
重新抛出相同的异常对象(而不是副本),则对该重新抛出的异常对象的并发访问可能会引入数据争用。引用特定异常的exception_ptr
对象数量的变化不会引入数据 种族。 - 后注]
关于rethrow
:
[[noreturn]] void rethrow_exception(exception_ptr p);
9要求:
p
不应为空指针。10抛出:p引用的异常对象。