信号处理程序陷入无限循环的原因及机制疑问
信号掩码误解与无限循环现象解析
核心误解澄清
- 信号掩码的作用不是丢弃信号,而是暂时挂起信号的递送,直到信号掩码不再包含该信号(通常是信号处理程序执行完毕,内核自动恢复掩码)。
- 默认情况下,当进程进入某个信号的处理程序时,内核会自动将该信号加入当前进程的信号掩码,防止处理过程中嵌套触发同类型信号,但这一屏蔽仅在处理程序运行期间有效;处理程序退出后,掩码会恢复为之前的状态,所有被挂起的信号会立即被递送。
测试代码的无限循环原因
你的代码中,两个信号处理程序互相发送对方的信号,形成了持续的挂起信号递送链:
main函数中调用kill(getpid(), SIGTSTP),触发ctrlZHandler,此时内核将SIGTSTP加入进程的信号掩码。- 在
ctrlZHandler中发送SIGINT,触发ctrlCHandler,内核将SIGINT也加入信号掩码(此时掩码同时包含SIGTSTP和SIGINT)。 - 在
ctrlCHandler中发送SIGTSTP,由于SIGTSTP处于当前掩码中,这个信号会被挂起,不会立即触发处理程序。 ctrlCHandler执行完毕退出,内核恢复到ctrlZHandler执行时的掩码状态(仅包含SIGTSTP),继续执行ctrlZHandler的剩余代码直到退出。ctrlZHandler退出后,内核恢复main函数的原始信号掩码(不包含SIGTSTP和SIGINT),此时之前挂起的SIGTSTP会立即被递送,再次进入ctrlZHandler,重复上述流程,形成无限循环,永远无法执行main中后续的cout语句。
SIGFPE与SIGINT测试的循环现象解释
当两个信号处理程序互相发送对方信号时,逻辑和上述案例一致:
- 进入
SIGFPE处理程序时,SIGFPE被加入掩码,此时发送SIGINT会触发其处理程序,SIGINT也被加入掩码。 - 在
SIGINT处理程序中发送SIGFPE,该信号会因SIGFPE在掩码中而被挂起。 SIGINT处理程序退出后,恢复到SIGFPE处理程序的掩码,SIGFPE处理程序退出后恢复原始掩码,挂起的SIGFPE被递送,再次触发处理程序,如此交替循环。
你的预期偏差在于:误以为信号掩码会永久阻止同类型信号的触发,但实际上掩码只是在处理程序运行期间临时屏蔽,处理程序退出后,所有被挂起的信号都会被立即递送,从而导致循环触发。
内容的提问来源于stack exchange,提问作者Shay
相关产品推荐
相关产品推荐

