SIGUSR1信号课堂练习:预测输出与实际输出不符的原因排查
为什么实际输出是
num=8而不是num=4? 你预测的错误核心在于忽略了信号处理期间的自动阻塞机制——当一个信号处理函数正在执行时,同类型的信号会被系统自动阻塞,不会立即触发新的处理,而是被挂起,直到当前信号处理函数执行完毕后才会被递送。下面我们一步步拆解代码的执行流程,看清每一步的变量变化:
初始状态
全局变量:num=0,y=1main函数注册SIGUSR1的处理函数后,调用f()。
步骤1:第一次进入f()
num=0≠2,执行kill(pid, SIGUSR1)发送信号。此时系统暂停f()的执行,切换到signal_hand处理信号。
注意:此时系统会自动将
SIGUSR1加入进程的信号掩码,后续收到的SIGUSR1会被挂起,直到当前信号处理完成。
步骤2:第一次执行signal_hand
- 重新注册
SIGUSR1处理函数(避免某些系统默认重置信号处理行为); num自增为1;- 调用
f()(第二次进入f()):num=1≠2,执行kill(pid, SIGUSR1)发送信号,但此时SIGUSR1被阻塞,这个信号不会立即处理,只是被挂起;- 执行
return 2*y,当前y=1,所以返回2;
y = y * f()→y=1*2=2;signal_hand执行完毕,返回。此时系统移除信号掩码中的SIGUSR1,之前挂起的SIGUSR1被递送,暂停之前的f()第一次执行,进入signal_hand第二次。
步骤3:第二次执行signal_hand
- 重新注册
SIGUSR1处理函数; num自增为2;- 调用
f()(第三次进入f()):num==2,直接返回当前的y=2;
y = y * f()→y=2*2=4;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。
你分析时遗漏的关键细节
- 信号阻塞机制:POSIX系统中,当处理某个信号时,该信号会被自动加入进程的信号掩码,同类型信号会被挂起而非立即嵌套处理。你可能误以为在
signal_hand中调用f()发送的信号会立即触发新的信号处理,导致y的计算路径被提前打断,但实际上这些信号要等到当前处理函数完成后才会执行。 - 变量
y的累积时机:由于信号被挂起,第二次signal_hand的执行是在第一次signal_hand完成之后,此时y已经被更新为2,而非你可能假设的保持初始值1,这最终导致f()第一次的返回值被放大到8。
内容的提问来源于stack exchange,提问作者Shimon Cohen
相关产品推荐
相关产品推荐

