我尝试使用信号向线程注入异常,但有时候异常没有被捕获。例如,以下代码:
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
如何使第二次威胁捕获异常? 注入异常是否更好?
答案 0 :(得分:2)
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块。
您可能会发现pthread取消支持更类似于您的需要,或者只是在某处添加这样的测试:
if (*(volatile int *)terminate_flag) throw terminate_exception();
答案 1 :(得分:1)
在Boost.thread中,可以通过调用相应的boost :: thread对象的interrupt()成员函数来中断线程。它使用pthread条件变量与线程通信,并允许您在线程代码中定义中断点。我会避免在C ++中使用pthread_kill。事实上,boost线程在代码中的任何地方都没有使用pthread_kill这一事实证实了这一点。