你真的懂Linux线程和信号的关系吗?
内容提要
本文讨论了进程中线程和信号的关系,包括线程组内共享信号处理函数,独立的信号阻塞集,私有和共享的未决信号队列。还介绍了设置线程阻塞信号集和处理收到信号的方式。致命信号会导致线程组退出。
延伸解读
信号处理函数共享,但阻塞集独立
同一线程组内的所有线程共享主线程的信号处理函数,这由task_struct的sighand成员指向同一sighand_struct实现。然而,每个线程拥有独立的信号阻塞集(blocked成员),可通过pthread_sigmask单独设置。这意味着一个线程可以屏蔽某信号,而其他线程仍能接收并处理它,为多线程信号处理提供了灵活性。
未决信号队列:私有与共享并存
每个线程有私有未决信号队列(pending成员),而线程组主线程还维护一个共享未决信号队列(signal成员)。当信号发送给主线程(如kill)且被阻塞时,会进入共享队列;发送给特定线程(如tkill、pthread_kill)且被阻塞时,则进入该线程的私有队列。主线程优先处理共享队列中的信号,其他线程仅在主线程不便处理时才会处理。
向指定线程发送信号的函数选择
tkill和tgkill可直接向指定线程发送信号,但tkill因线程ID可能被复用而不安全,应尽量少用;tgkill通过线程组ID和线程ID更安全。pthread_kill和pthread_sigqueue是POSIX线程接口,后者还能附带数据。这些函数允许精确控制信号的目标线程,但需注意信号阻塞集和未决队列的交互。
致命信号导致整个线程组退出
当线程收到致命信号(即默认动作是终止进程的信号)时,不仅该线程会终止,整个线程组都会退出。这一机制实现了线程组的统一退出管理,确保进程内所有线程同时结束,避免部分线程残留。理解这一点对多线程程序的信号处理设计至关重要。
Q&A
线程和信号之间的关系是什么?
线程与信号的关系包括共享信号处理函数、独立的信号阻塞集、私有和共享的未决信号队列,以及收到致命信号时线程组将退出。
如何设置线程的信号阻塞集?
可以通过pthread_sigmask函数设置线程的阻塞信号集,使用时需要指定修改方式和新的信号屏蔽字集合。
什么是共享未决信号队列?
共享未决信号队列是指线程组的主线程拥有的队列,其他线程可以共享该队列中的信号。
致命信号会对线程组产生什么影响?
收到致命信号时,整个线程组将统一退出,以实现线程的统一管理。
tkill和pthread_kill函数有什么区别?
tkill函数用于向指定线程发送信号,而pthread_kill函数用于向指定线程发送信号的同时可以指定线程标识符。
线程的信号处理是如何优先级排序的?
主线程优先处理共享未决信号队列中的信号,其他线程在主线程不方便处理时才会处理这些信号。