std::exception_ptr能否存储__cxxabi::__forced_unwind?代码合法性问询
关于GNU/Linux下
pthread_cancel异常传递的安全性问题 背景与问题
在GNU/Linux系统中,pthread_cancel通过类型为__cxxabi::__forced_unwind的特殊异常实现:线程被取消时会抛出该异常并展开栈。因此捕获catch (...)的异常后必须始终重抛,绝对不能吞掉__forced_unwind(否则会触发运行时错误)。
我的问题是:如果不直接吞掉该异常,先用std::current_exception()将__forced_unwind打包为std::exception_ptr,再通过std::rethrow_exception()重抛,这种操作是否安全?
代码示例
} catch (...) { handleException(); } // elsewhere void handleException() { try { std::rethrow_exception(std::current_exception()); } catch (const std::exception &e) { log(e.what()); return; } // 吞掉已知类型异常 catch (...) { log("unknown exception caught"); throw; } // 重抛未知异常,包括__forced_unwind }
回答
这种写法是安全且具有良好定义的,具体说明如下:
1. C++标准层面的合法性
std::current_exception()和std::rethrow_exception()是C++标准库明确规定的异常传递机制,标准保证:
- 在异常处理期间调用
current_exception(),会创建指向当前异常的有效std::exception_ptr; - 后续调用
rethrow_exception()传入该指针,会准确还原原始异常对象,无论其具体类型是什么,包括实现定义的特殊异常。
只要最终没有吞掉__forced_unwind(如代码中最后catch (...)分支的throw;操作),线程的取消流程就能正常完成,不会触发运行时错误。
2. GNU实现层面的兼容性
__cxxabi::__forced_unwind作为GNU C++运行时为pthread_cancel实现的特殊栈展开异常,完全支持通过std::exception_ptr进行传递。GNU运行时会正确识别重抛后的该异常,继续完成线程取消的栈展开流程。
适用范围的规定
- 通用规则由C++标准规定:
std::exception_ptr的传递和重抛行为,在所有符合C++标准的实现中通用; - 特定场景的有效性由POSIX标准和GNU C++运行时实现共同保证:这种写法仅在遵循POSIX的GNU/Linux环境下有效——因为
pthread_cancel是POSIX接口,而__cxxabi::__forced_unwind是GNU的特定实现细节。
内容的提问来源于stack exchange,提问作者Marc Mutz - mmutz
相关产品推荐
相关产品推荐

