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

SIGUSR1信号课堂练习:预测输出与实际输出不符的原因排查

为什么实际输出是num=8而不是num=4?

你预测的错误核心在于忽略了信号处理期间的自动阻塞机制——当一个信号处理函数正在执行时,同类型的信号会被系统自动阻塞,不会立即触发新的处理,而是被挂起,直到当前信号处理函数执行完毕后才会被递送。下面我们一步步拆解代码的执行流程,看清每一步的变量变化:

初始状态

全局变量:num=0,y=1
main函数注册SIGUSR1的处理函数后,调用f()。


步骤1:第一次进入f()

num=0≠2,执行kill(pid, SIGUSR1)发送信号。此时系统暂停f()的执行,切换到signal_hand处理信号。

注意:此时系统会自动将SIGUSR1加入进程的信号掩码,后续收到的SIGUSR1会被挂起,直到当前信号处理完成。

步骤2:第一次执行signal_hand

  1. 重新注册SIGUSR1处理函数(避免某些系统默认重置信号处理行为);
  2. num自增为1;
  3. 调用f()(第二次进入f()):
    • num=1≠2,执行kill(pid, SIGUSR1)发送信号,但此时SIGUSR1被阻塞,这个信号不会立即处理,只是被挂起;
    • 执行return 2*y,当前y=1,所以返回2;
  4. y = y * f() → y=1*2=2;
  5. signal_hand执行完毕,返回。此时系统移除信号掩码中的SIGUSR1,之前挂起的SIGUSR1被递送,暂停之前的f()第一次执行,进入signal_hand第二次。

步骤3:第二次执行signal_hand

  1. 重新注册SIGUSR1处理函数;
  2. num自增为2;
  3. 调用f()(第三次进入f()):
    • num==2,直接返回当前的y=2;
  4. y = y * f() → y=2*2=4;
  5. signal_hand执行完毕,返回,回到被暂停的f()第一次执行。

步骤4:回到第一次f()继续执行

执行return 2*y,当前y=4,所以返回2*4=8。

步骤5:main函数输出

x接收f()的返回值8,执行printf("num = %d\n", x),最终输出num=8。


你分析时遗漏的关键细节

  1. 信号阻塞机制:POSIX系统中,当处理某个信号时,该信号会被自动加入进程的信号掩码,同类型信号会被挂起而非立即嵌套处理。你可能误以为在signal_hand中调用f()发送的信号会立即触发新的信号处理,导致y的计算路径被提前打断,但实际上这些信号要等到当前处理函数完成后才会执行。
  2. 变量y的累积时机:由于信号被挂起,第二次signal_hand的执行是在第一次signal_hand完成之后,此时y已经被更新为2,而非你可能假设的保持初始值1,这最终导致f()第一次的返回值被放大到8。

内容的提问来源于stack exchange,提问作者Shimon Cohen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 06:08:11