如果多线程 Linux 进程收到信号会发生什么?

pet*_*erh 29 linux signals posix multithreading

如果 Unix (Posix) 进程接收到信号,信号处理程序将运行。

在多线程进程中它会发生什么?哪个线程接收信号?

在我看来,信号 API 应该被扩展来处理(即信号处理程序的线程应该能够被确定),但是在网上寻找信息我只在 linux 内核邮件列表和上发现了长达一年的火焰不同的论坛。据我了解,Linus 的概念不同于 Posix 标准,首先构建了一些兼容层,但现在 Linux 遵循 posix 模型。

目前的状态是什么?

Kus*_*nda 16

POSIX 中关于“基本原理:系统接口一般信息”中“信号生成和传递”的条目说

为进程生成的信号仅传递给一个线程。因此,如果有多个线程有资格接收信号,则必须选择一个。线程的选择完全取决于实现,以允许尽可能广泛的符合实现的实现,并在不同线程之间传递的难易度存在差异时,使实现可以自由地将信号传递给“最容易”的线程。

signal(7)Linux 系统上的手册:

可以为整个进程(例如,在使用 发送时kill(2))或为特定线程(例如,某些信号,例如 SIGSEGV 和 SIGFPE,作为执行特定机器的结果而生成)生成(因此未决)信号 -语言指令是线程定向的,使用pthread_kill(3))的特定线程的信号也是如此。进程导向的信号可以被传递到当前没有阻塞信号的线程中的任何一个。如果多个线程的信号被解除阻塞,那么内核会选择一个任意线程来传递信号。

并在pthreads(7)

线程具有不同的备用信号堆栈设置。但是,新线程的备用信号堆栈设置是从创建它的线程复制的,因此线程最初共享备用信号堆栈(在内核 2.6.16 中已修复)。

来自pthreads(3)OpenBSD 系统的手册(作为替代方法的示例):

信号处理程序通常在当前正在执行的线程的堆栈上运行。

(我目前不知道在多处理器机器上同时执行多个线程时如何处理)

POSIX 线程的旧 LinuxThread 实现只允许信号针对不同的单个线程。从pthreads(7)Linux系统上:

LinuxThreads 不支持进程导向信号的概念:信号只能发送到特定线程。


pet*_*erh 5

扩展已接受的答案,有一个更实用的观点,我在这里找到的内容。

本质如下:

信号处理程序是每个进程的,但信号掩码是每个线程的。

  1. 因此,如果我们在任何线程上安装/卸载信号处理程序(使用signal()sigaction()),它将影响所有线程。
  2. 如果进程收到信号,则处理程序将仅在单个线程上执行。该线程是在其中伪随机选择的,其信号掩码接受它。我的实验表明,它始终是 pid 最少的线程。*
  3. 发送到任何线程的信号都被视为发送到主进程的信号。因此,如果一个线程收到信号,很可能另一个线程将执行处理程序。如果我们看到线程(由tids、线程 id 标识)将被视为屏蔽进程(由pids标识),并且发送到 a 的信号tid将被转发到它们的pid.
  4. 对于信号处理程序的执行,在其信号掩码中,给定的信号编号会被自动屏蔽。这是为了防止在信号突发中执行堆栈信号处理程序。这可以通过呼叫的SA_NODEFER标志来改变sigaction(...)
  5. (3) 和 (4) 导致在信号突发的情况下,系统可能最并行地分配信号处理程序。
  6. 但是,如果我们使用 设置了 sigaction SA_NODEFER,则始终相同的线程将获得信号并且它们将堆叠

*评论说它也可能是由首先创建的线程造成的。两者都符合 posix 标准,所以不要在你的代码中相信它。