You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux信号程序多次运行cpt返回值不一致问题原因分析

问题复现代码

你用于测试Linux信号机制的代码如下:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int cpt = 0;
void handler (int sig) {
     cpt++ ;
}
int main() {
  int i;
  signal(SIGCHLD, handler);
  for (i = 0; i < 5; i++) {
       if (fork() == 0) {
           exit(0);
       }
   }
   while (wait(NULL) != -1) ;
   printf("cpt = %d\n", cpt);
   return 0;
}

你预期程序固定输出cpt = 5,但实际运行时会随机返回3、4、5三种结果。

根本原因

输出随机波动的核心原因是:Linux下编号1~31的标准非实时信号不支持排队机制。当同一种信号处于待处理状态(即信号已经触发,但还没来得及递送到用户态执行注册的处理函数)时,无论后续该信号又触发了多少次,内核都只会保留1个待处理信号实例,不会记录该信号的实际触发总次数,多触发的信号会被直接合并丢弃。

对应代码的具体执行逻辑:

  • 你通过signal()注册了SIGCHLD信号的处理函数,按照机制设计,每个子进程终止时内核都会向父进程发送SIGCHLD信号通知。
  • 循环创建的5个子进程没有额外业务逻辑,调用exit(0)后会立刻终止,多个子进程很可能在极短的时间窗口内先后退出。如果前一个SIGCHLD信号还没完成递送、还没执行handler累加逻辑,后续到达的同类型SIGCHLD信号不会逐个排队等待处理,只会被合并标记为“存在待处理SIGCHLD”,最终只会触发一次handler执行,cpt也就只会累加1次。
  • 程序每次运行时,操作系统的进程调度时序、信号递送的具体时机都是不确定的:如果5次SIGCHLD触发时都没有出现待处理状态的重叠,没有信号被合并,最终就输出5;如果有1次合并(两次信号触发重叠被合并为一次)就输出4;如果有2次合并就输出3,这就是结果随机的来源。

需要注意的是,代码末尾的while (wait(NULL) != -1)逻辑确实可以正确回收全部5个退出的子进程,但回收子进程的动作不会补触发那些被合并丢弃的SIGCHLD信号,因此cpt的计数永远只等于实际被递送到用户态执行处理函数的信号次数,和子进程退出的总次数没有必然的相等关系。

内容的提问来源于stack exchange,提问作者Rafik Bouloudene

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 09:18:21