实时信号支持fifo排队但队列长度受限(默认1024),超限时sigqueue()返回eagain而非静默丢弃;可通过ulimit -i调整rlimit_sigpending限制,并需在处理函数中避免阻塞以防止积压。

Linux 中实时信号本身不会发生“队列溢出”意义上的丢弃,但存在队列容量限制和资源耗尽风险——这与非实时信号的“不排队、可能丢失”有本质区别。理解这一点是避免误操作的关键。
实时信号天然支持排队,但队列长度有限
实时信号(SIGRTMIN 至 SIGRTMAX,通常 34–64)由内核为每个进程维护独立的实时信号队列,同一信号可多次发送并按 FIFO 顺序保存。但该队列不是无限的:
- 每个进程的实时信号队列长度默认为 1024(由
RLIMIT_SIGPENDING限制); - 超出上限后,
sigqueue()调用会失败,返回-1并置errno = EAGAIN; - 此时信号不会被静默丢弃,而是直接拒绝入队,调用方需主动处理错误。
如何检查和调整队列容量
队列上限取决于进程的 sigpending 资源限制,可通过以下方式查看和修改:
- 查看当前限制:
ulimit -i(单位为信号数); - 临时提高(需权限):
ulimit -i 2048; - 永久设置:在
/etc/security/limits.conf中添加* soft sigpending 2048 * hard sigpending 2048
- 注意:
RLIMIT_SIGPENDING同时约束sigqueue()和pthread_sigqueue(),也影响 POSIX 线程的实时信号接收能力。
避免队列积压的工程实践
实时信号常用于高频率事件通知(如传感器采样触发、定时器到期),若处理函数执行过慢或阻塞,队列会快速填满:
- 处理函数应尽量轻量,避免
malloc、文件 I/O、锁竞争等可能延迟的操作; - 可在信号处理中仅设置原子标志(如
sig_atomic_t ready = 1),主循环轮询该标志再做重载处理; - 对高频信号源(如
timer_create(CLOCK_MONOTONIC, ...)),考虑合并逻辑:例如用一个信号携带计数(通过sigqueue()的union sigval传sival_int),而非每毫秒发一次信号。
不要混淆:这不是 TCP 队列溢出
有人误将“信号队列满”类比为 listen() 的 backlog 溢出,这是概念错位:
- TCP 队列溢出导致连接被内核静默丢弃(需调
somaxconn等参数); - 实时信号队列满则
sigqueue()明确失败,程序可捕获并降级(如切为轮询、记录告警、限频发送); - 二者机制无关,不能套用同一套调优思路。
基本上就这些。











