【问题标题】:Catching signals such as SIGSEGV and SIGFPE in multithreaded program在多线程程序中捕获 SIGSEGV 和 SIGFPE 等信号
【发布时间】:2013-12-16 18:28:00
【问题描述】:

我正在尝试为在 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 吗?

我找到了Signal handling with multiple threads in Linux 的问题,但我不知道哪些信号是线程特定的以及如何捕获它们。

【问题讨论】:

  • 三十年来我一直认为程序不应该捕获 SIGSEGV:它们应该被调试。
  • 我同意。捕获 SIGSEGV 或类似系统的全部目的是从程序中获取最后记录的信息,以帮助找到导致程序首先失败的错误。
  • 所以暂时禁用日志系统中的缓冲,运行程序,查看日志,调试程序。
  • 您是否尝试在信号处理程序中等待记录器的队列变空,然后继续正常操作? Justa 的问题,不知道这是否可能。
  • 如果您的程序正在抛出 SIGSEGV(或 SSIGBUS),那么您在没有特定仪器的情况下就在某条小溪上。我认为游戏结束了

标签: c++ linux multithreading posix


【解决方案1】:

我同意 cmets:在实践中捕获和处理 SIGSEGV 通常是一件坏事。

SIGSEGV 被传递到一个特定 线程(参见this),该线程运行机器指令并访问了某个非法地址。

因此,您不能在其他线程中运行专用于捕获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 外部寻呼机效率不高。见this answer...

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

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

【讨论】:

  • 如果使用 mprotect() 在一定时间内专门保护内存区域免受线程访问,则 SIGSEGV 处理程序确实可以移植,因为后续的 SEGV 不会是“随机无效内存访问”需要复杂的修复。当然,应该检查故障地址是否确实在受保护范围内,如果不是,则中止程序,因为在这种情况下 SEGV 来自无效访问。
猜你喜欢
  • 1970-01-01
  • 2013-04-18
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多