linux处理sigalrm需三步:先用signal或sigaction注册安全的信号处理函数,再用alarm或setitimer设置定时器,最后在handler中执行轻量逻辑;注意信号不排队、系统调用可能被中断、避免非异步信号安全函数。

Linux中处理定时器产生的SIGALRM信号,核心在于三步:注册信号处理函数、设置定时器、在信号到达时执行自定义逻辑。默认情况下,进程收到SIGALRM会直接终止,所以必须显式安装处理函数,否则“闹钟一响就关机”,毫无实用价值。
必须先用signal或sigaction安装处理函数
内核发送SIGALRM后,若未提前注册处理方式,就按默认动作(terminate)执行。因此第一步永远是绑定回调:
- 用signal(SIGALRM, handler)最简单,适合基础场景;
- 用sigaction()更健壮,可屏蔽其他信号、避免重入、支持sa_flags(如SA_RESTART),推荐生产环境使用;
- handler函数不能调用非异步信号安全函数(如printf、malloc),应尽量只修改全局volatile变量或写入pipe/fd;
用alarm或setitimer触发SIGALRM
alarm()提供秒级单次定时,setitimer()支持微秒级及周期性触发,二者底层都依赖进程独占的定时器资源:
- alarm(seconds):设一个倒计时,到期发一次SIGALRM;再次调用会覆盖前值,返回上次剩余时间;设为0可取消;
- setitimer(ITIMER_REAL, &newval, &oldval):通过itimerval结构体控制,it_value是首次超时时间,it_interval是非零值时的自动重载周期;
- 注意:alarm和ITIMER_REAL共享同一硬件定时器,混用会相互覆盖;
信号递送期间的常见陷阱与应对
SIGALRM不是“准时快递”,它的到达时机受系统调度、信号阻塞、以及被中断的系统调用影响:
- 阻塞式系统调用(如read、accept、sleep)可能被SIGALRM中断,返回-1并置errno为EINTR,需检查并重试;
- 若在信号处理函数中调用了不安全函数(如printf),可能导致死锁或崩溃;
- 多个SIGALRM不会排队——未决状态只记录“有/无”,重复发送不累积;如需节拍控制,应在handler里立刻重设alarm或setitimer;
- 进程处于TASK_INTERRUPTIBLE状态(如等待磁盘IO)时,alarm仍继续倒计时,不受影响;
典型应用场景示例
两类高频用途可体现设计逻辑:
- 函数执行超时保护:在调用可能卡住的系统调用(如connect)前设alarm(5),handler中longjmp跳出或设置标志位,主流程检查后主动退出;
- 周期性轻量任务:用setitimer设置200ms周期,handler中仅更新一个volatile计数器或向eventfd写入,主线程select/poll监听该fd实现解耦响应;











