我正在尝试为在linux上运行的程序编写多线程日志记录系统.
在主程序线程中调用日志记录系统会将包含要记录的数据的数据结构推送到FIFO队列中.专用线程选择队列的数据并输出数据,而程序主线程继续其任务.
如果主程序导致SIGSEGV或其他信号被引发,我需要在终止之前确保队列为空.
我的计划是使用pthread_sigmask http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html阻止除一个线程之外的所有信号,但是在http://man7.org上读取信号列表/linux/man-pages/man7/signal.7.html我注意到:
可以为整个过程(例如,当使用kill(2)发送时)或针对特定线程(例如,某些信号,例如SIGSEGV和SIGFPE,>生成的信号)生成(并因此待决)信号执行特定机器语言指令的步骤是线程定向的,使用pthread_kill(3)的特定线程的信号也是如此.
如果我在所有线程上阻塞SIGSEGV但是一个专用于捕获信号的线程,那么它会捕获由不同线程引发的SIGSEGV吗?
我在Linux中发现了使用多个线程进行信号处理的问题,但我对于哪些信号是特定于线程以及如何捕获它们一无所知.
我同意这些评论:在实践中,捕捉和处理SIGSEGV
往往是一件坏事.
并SIGSEGV
传递给一个特定的线程(见这个),一个运行机器指令的线程访问某个非法地址.
所以你不能运行专门用于捕获SIGSEGV
其他线程的线程.而你也不能轻易使用signalfd(2)对SIGSEGV
...
捕获(并且通常从其信号处理程序返回)SIGSEGV
是一个复杂的处理器特定的东西(它不能是"可移植的C代码").您需要检查并更改处理程序中的机器状态,即修改地址空间(通过调用mmap(2)等...)或修改当前线程的寄存器状态.因此,使用的sigaction(2)与SA_SIGINFO
和改变由第三个参数(类型的指示的机器特定状态ucontext_t*
的信号处理程序的).然后深入到它的处理器特定 uc_mcontext
字段.有乐趣改变个别寄存器等...如果你不改变故障线程的机器状态,执行将恢复(从SIGSEGV
处理程序返回后)与之前相同的情况,并SIGSEGV
立即发送另一个信号...或者简单地说,不要从SIGSEGV
处理程序中正常返回(例如使用siglongjmp(3)或abort(3)或_exit(2) ......).
即使你碰巧做了这一切,也有传言说Linux内核对这种执行并不是非常有效.因此有传言说在Linux上尝试以这种方式模仿Hurd/Mach外部寻呼机效率不高.看到这个答案 ......
当然,信号处理程序应该只调用(参见信号(7)以获得更多)异步信号安全功能.特别是,您原则上不fprintf
能从它们调用(并且您可能无法可靠地使用您的日志记录系统,但它可以在大多数情况下工作,但不是所有情况).
我在说SIGSEGV
也持有SIGBUS
和SIGFPE
(和其他特定线程异步信号,如果存在的话).