我尝试使用信号将异常注入(inject)线程,但有时异常未被捕获。例如下面的代码:
void _sigthrow(int sig)
{
throw runtime_error(strsignal(sig));
}
struct sigaction sigthrow = {{&_sigthrow}};
void* thread1(void*)
{
sigaction(SIGINT,&sigthrow,NULL);
try
{
while(1) usleep(1);
}
catch(exception &e)
{
cerr << "Thread1 catched " << e.what() << endl;
}
};
void* thread2(void*)
{
sigaction(SIGINT,&sigthrow,NULL);
try
{
while(1);
}
catch(exception &e)
{
cerr << "Thread2 catched " << e.what() << endl; //never goes here
}
};
如果我尝试像这样执行:
int main()
{
pthread_t p1,p2;
pthread_create( &p1, NULL, &thread1, NULL );
pthread_create( &p2, NULL, &thread2, NULL );
sleep(1);
pthread_kill( p1, SIGINT);
pthread_kill( p2, SIGINT);
sleep(1);
return EXIT_SUCCESS;
}
我得到以下输出:
Thread1 catched Interrupt
terminate called after throwing an instance of 'std::runtime_error'
what(): Interrupt
Aborted
如何让第二个威胁捕获异常? 关于注入(inject)异常有更好的主意吗?
最佳答案
G++ 假定异常只能从函数调用中抛出。如果您要违反此假设(例如,通过将它们从信号处理程序中抛出),您需要在构建程序时将 -fnon-call-exceptions
传递给 G++。
但是请注意,这会导致 G++:
Generate code that allows trapping instructions to throw
exceptions. Note that this requires platform-specific runtime
support that does not exist everywhere. Moreover, it only allows
_trapping_ instructions to throw exceptions, i.e. memory
references or floating point instructions. It does not allow
exceptions to be thrown from arbitrary signal handlers such as
`SIGALRM'.
这意味着从一些随机代码中间抛出异常是不安全的。您只能排除 SIGSEGV
、SIGBUS
和 SIGFPE
,并且只有当您通过 -fnon-call-exceptions
并且它们是由于运行代码中的错误而触发的。这在线程 1 上起作用的唯一原因是,由于 usleep()
调用的存在,G++ 被迫假设它可能会抛出异常。对于线程 2,G++ 可以看到不存在陷阱指令,并消除 try-catch block 。
您可能会发现 pthread 取消支持更符合您的需要,或者只需在某处添加这样的测试:
if (*(volatile int *)terminate_flag) throw terminate_exception();
关于c++ - 向 pthread 注入(inject)运行时异常有时会失败。如何解决?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2696171/