一尘不染

在多线程程序中捕获信号,例如SIGSEGV和SIGFPE

linux

我正在尝试为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中发现了使用多个线程进行信号处理的问题,但是对于哪些信号是线程特定的以及如何捕获它们,我一无所知。


阅读 461

收藏
2020-06-03

共1个答案

一尘不染

我同意以下意见:在实践中,捕获和处理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外部寻呼机并不是很有效。 …

当然,信号处理程序应该只调用异步信号安全函数有关更多信息,请参见signal(7))。特别是,原则上您不能fprintf从他们那里打电话(并且您可能无法 可靠地
使用您的日志记录系统,但是它可以在大多数情况下(但不是在所有情况下)工作)。

我所说的SIGSEGV还适用于SIGBUSSIGFPE(以及其他特定于线程的异步信号,如果它们存在的话)。

2020-06-03