在 Linux 中,当一个程序(可能有多个线程)接收到一个信号(如 SIGTERM 或 SIGHUP)时会发生什么?
哪个线程拦截了信号?多个线程可以得到相同的信号吗?是否有专门用于处理信号的特殊线程?如果不是,处理信号的线程内部会发生什么?信号处理程序完成后如何恢复执行?
最佳答案
pthreads(7)
描述了 POSIX.1 要求一个进程中的所有线程共享属性,包括:
POSIX.1 还要求每个线程的某些属性不同,包括:
信号掩码(pthread_sigmask(3)
)
备用信号堆栈 (sigaltstack(2)
)
Linux 内核的 complete_signal
例程有以下代码块——注释非常有用:
/*
* Now find a thread we can wake up to take the signal off the queue.
*
* If the main thread wants the signal, it gets first crack.
* Probably the least surprising to the average bear.
*/
if (wants_signal(sig, p))
t = p;
else if (!group || thread_group_empty(p))
/*
* There is just one thread and it does not need to be woken.
* It will dequeue unblocked signals before it runs again.
*/
return;
else {
/*
* Otherwise try to find a suitable thread.
*/
t = signal->curr_target;
while (!wants_signal(sig, t)) {
t = next_thread(t);
if (t == signal->curr_target)
/*
* No thread needs to be woken.
* Any eligible threads will see
* the signal in the queue soon.
*/
return;
}
signal->curr_target = t;
}
/*
* Found a killable thread. If the signal will be fatal,
* then start taking the whole group down immediately.
*/
if (sig_fatal(p, sig) &&
!(signal->flags & SIGNAL_GROUP_EXIT) &&
!sigismember(&t->real_blocked, sig) &&
(sig == SIGKILL || !p->ptrace)) {
/*
* This signal will be fatal to the whole group.
*/
因此,您会看到 您 负责信号的传递位置:
如果您的进程已将信号的处置设置为 SIG_IGN
或 SIG_DFL
,则所有线程都会忽略该信号(或默认 -- kill、core 或 ignore) .
如果您的进程已将信号的处置设置为特定的处理程序例程,那么您可以通过使用 pthread_sigmask(3)
操作特定线程信号掩码来控制哪个线程将接收信号。 .您可以指定一个线程来管理所有这些,或者为每个信号创建一个线程,或者这些选项的任意组合用于特定信号,或者您依赖 Linux 内核当前将信号传递到主线程的默认行为。
然而,根据 signal(7)
,有些信号是特殊的。手册页:
A signal may be generated (and thus pending) for a process as a whole (e.g., when sent using kill(2)) or for a specific thread (e.g., certain signals, such as SIGSEGV and SIGFPE, generated as a consequence of executing a specific machine-language instruction are thread directed, as are signals targeted at a specific thread using pthread_kill(3)). A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked. If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal.
https://stackoverflow.com/questions/11679568/