如何正确终止信号处理程序中的线程?

时间:2014-09-20 15:59:35

标签: c linux multithreading signals posix

我想为SIGSEGV,SIGILL和可能的其他几个信号设置一个信号处理程序,而不是终止整个过程,只是终止有问题的线程并且可能在某处设置一个标志,以便监控线程可以抱怨并启动另一个线程。我不确定有没有一种安全的方法可以做到这一点。 Pthreads似乎提供退出当前线程的函数,以及取消另一个线程,但这些可能会调用一堆退出处理程序。即使他们不这样做,似乎有很多情况下它们不是异步信号安全的,尽管这些情况可能是可以避免的。是否有一个我可以调用的低级函数只是破坏了线程?假设我以异步信号安全的方式修改自己的数据结构,并且没有获取互斥锁,那么pthread /其他全局数据结构是否只能通过终止于SIGSEGV的线程处于不一致状态?我想到了malloc,但malloc本身不应该是SIGSEGV / SIGILL,除非libc是错误的。我意识到POSIX在这里非常保守,并且不做任何保证。只要在实践中有一种方法可以做到这一点,我很高兴。分叉不是一种选择,顺便说一句。

1 个答案:

答案 0 :(得分:2)

如果SIGSEGV / SIGILL /等。在您自己的代码中发生 ,信号处理程序将不会在异步信号上下文中运行(它基本上是一个同步信号,但如果它发生在标准库函数中,它仍然是一个AS上下文),所以您可以合法地从信号处理程序中调用pthread_exit。但是,仍有一些问题使这种做法变得可疑:

  • SIGSEGV / SIGILL /等。除非您通过raisekillpthread_killsigqueue等生成行为,否则永远不会出现在行为定义的程序中(在某些特殊情况下, 将是异步信号)。否则,它们表示程序具有未定义的行为。如果程序调用了未定义的行为,则所有投注均已关闭。 UB未及时隔离到特定线程或特定序列。如果程序具有UB,则其整个输出/行为毫无意义。

  • 如果程序的状态已损坏(例如由于访问后free,使用无效指针,缓冲区溢出,......)很可能第一次故障访问将在部分内部发生标准库(例如在malloc内)而不是在您的代码中。在这种情况下,信号处理程序在AS安全上下文中运行,不能调用pthread_exit。当然程序已经有了UB(参见上面的观点),但即使你想假装这不是问题,你仍然会遇到麻烦。

如果您的程序遇到这类崩溃,您需要查找原因并进行修复,而不是尝试使用信号处理程序修补它。 Valgrind是你的朋友。如果那是不可能的,那么最好的办法就是将崩溃的代码隔离到单独的进程中,在这些进程中,如果异步崩溃,可以推断出发生的情况,而不是在同一进程中使用崩溃的代码(有关代码行为的任何进一步推理无效)一旦你知道它崩溃了。)