在由于异常而展开时处理C++析构函数中的pthread取消点
Handling pthread cancellation points in C++ destructors when unwinding due to an exception
我正试图实现一个范围保护类,但在Linux上遇到了取消点的问题。根据我的发现,Linux在异常方面实现了pthread取消,其中异常不能在用户的catch块中处理(即必须重新抛出)。这会导致以下范围保护实现出现问题,该实现试图忽略其关联函数可能引发的任何异常:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <functional>
struct scope_guard {
template <typename T>
scope_guard(T func) : function_(func) {}
~scope_guard() {
try {
function_();
}
catch (...) {}
}
std::function<void()> function_;
};
extern "C" {
void* thread_func(void*) {
try {
scope_guard guard( [](void) {
// wait for a cancellation event
while (true) {
pthread_testcancel();
}
});
throw int();
}
catch (int&) {}
return 0;
}
}
int main(void) {
pthread_t thread;
int ret;
if (0 != (ret = pthread_create(&thread, NULL, &thread_func, NULL))) {
fprintf(stderr, "pthread_create failed: %dn", ret);
return 1;
}
sleep(1);
if (0 != (ret = pthread_cancel(thread))) {
fprintf(stderr, "pthread_cancel failed: %dn", ret);
return 1;
}
void* thread_ret;
if (0 != (ret = pthread_join(thread, &thread_ret))) {
fprintf(stderr, "pthread_join failed: %dn", ret);
return 1;
}
return 0;
}
~scope_guard() {
try {
function_();
}
catch (abi::__forced_unwind&) {
throw;
}
catch (...) {}
}
这在Solaris、HPUX和AIX上运行良好,但在Linux上会产生以下错误并中止:
FATAL: exception not rethrown
这是由~scope_guard
中的catch (...)
块引起的,该块捕获但不重新引发pthread取消异常。
基于本文,处理这些取消异常的推荐方法是从catch (...)
块重新抛出异常,或者显式捕获并重新抛出取消异常,如下所示:
~scope_guard() {
try {
function_();
}
catch (abi::__forced_unwind&) {
throw;
}
catch (...) {}
}
然而,这两种方法都会导致从这个解构函数抛出一个新的异常,这会导致问题终止,因为现有的异常已经在展开堆栈的过程中。在我的测试中,报告了以下内容:
terminate called without an active exception
有没有办法在Linux上处理这种情况?
~scope_guard()
的第二个版本是正确的。
这里的问题是,你为什么在thread_func()
中使用throw int()
?删除它,您的代码将正常工作。
如果你真的想抛出int,你应该写如下:
void* thread_func(void*) {
scope_guard guard( [](void) {
// wait for a cancellation event
while (true) {
pthread_testcancel();
throw int(); // Throw either here
}
throw int(); // Or here
});
return 0;
}
请注意,您应该将所有"可能的抛出代码"放在scope_guard的函数中。
相关文章:
- 什么时候调用组成单元对象的析构函数
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内联映射初始化的动态atexit析构函数崩溃
- 什么时候调用析构函数
- 优先顺序:智能指针和类析构函数
- C++-明确何时以及如何调用析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 在c++中使用向量时,如何调用构造函数和析构函数
- 重载运算符new[]的行为取决于析构函数
- 我需要知道编译器如何在cpp中使用析构函数
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 析构函数调用
- 通过引用传递-为什么要调用这个析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- C++成员的析构函数顺序与shared_ptr
- C++ 防止在映射中放置()时调用析构函数
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- 调用析构函数以释放动态分配的内存
- 不命名构造函数和析构函数上的类型错误