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

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

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

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

我认为,信号 API 应该扩展以处理该问题(即应该能够确定信号处理程序的线程),但在网上搜索信息时,我只在 Linux 内核邮件列表和不同论坛上找到了一年多的争论。据我了解,Linus 的概念与 Posix 标准不同,首先构建了一些兼容层,但现在 Linux 遵循 posix 模型。

目前的状况如何?

答案1

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 不支持进程定向信号的概念:信号只能发送到特定线程。

答案2

扩展已接受的答案,有一个更实际的观点,我发现了什么这里

本质如下:

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

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

*评论说它也可能是首先创建的线程。两者都符合 posix 标准,因此不要相信您的代码中的它。

相关内容