linux多线程中,信号默认发给任意一个未屏蔽该信号的线程:内核从就绪且未阻塞该信号的线程中选择一个(通常tid最小)递送;所有线程共享同一信号处理函数,但各有独立信号掩码;kill()发进程级信号由内核选线程,pthread_kill()则直发指定线程。

信号在多线程中默认发给任意一个未屏蔽该信号的线程
Linux 遵循 POSIX 标准:进程级信号(如 SIGINT、SIGSEGV、SIGTERM)发送给整个进程,内核会从中挑选一个**当前未阻塞该信号**的线程来递送。这个选择是内核决定的,不可预测——不是随机“乱选”,而是从就绪且未屏蔽该信号的线程中选一个,通常优先选 tid 最小的可用线程。
所有线程共享同一套信号处理函数
无论哪个线程注册了 signal() 或 sigaction(),该处理函数对整个进程生效。也就是说:
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 主线程注册的 SIGUSR1 处理器,子线程触发 SIGUSR1 也会进入同一个函数
- 后注册的覆盖先注册的,不存在“线程专属 handler”
- 但每个线程有独立的 信号掩码(signal mask),可用 pthread_sigmask() 单独设置阻塞哪些信号
关键区别:发送目标不同,行为完全不同
要控制信号去向,得看你是怎么发的:
- 用 kill(getpid(), sig) 或 raise(sig) → 发给进程 → 内核选线程递送
- 用 pthread_kill(tid, sig) → 直接发给指定线程 → 仅该线程能收到(即使它屏蔽了,信号也会挂起在它的 pending 集合里)
- 用 sigwait() 在某线程中等待 → 该线程主动“收信号”,此时若同时有 handler 注册,sigwait 优先级更高,信号不会进 handler
安全实践:推荐单线程专注处理信号
避免多个线程竞争处理同一类信号引发竞态或重入问题。常见做法是:
- 主线程(或专用信号线程)调用 pthread_sigmask() 解除关键信号(如 SIGQUIT、SIGUSR1)的阻塞
- 其他工作线程一律屏蔽这些信号(防止意外中断)
- 在信号线程中用 sigwait() 同步等待,收到后转为内部事件(如写 pipe、发条件变量)交由业务逻辑处理
- 不依赖异步 signal handler 做复杂操作(如 malloc、printf、锁操作),因其上下文不可控










