Linux信号问题:自定义SIGINT信号处理函数为何仅生效一次?
问题原因与解决方法
核心原因
你使用的signal函数属于传统UNIX信号机制,它有一个关键特性:当信号处理函数被触发执行一次后,系统会自动将该信号的处理动作重置为默认行为(SIG_DFL)。因此第一次Ctrl+C触发handler2执行后,SIGINT的处理方式变回默认的终止进程,第二次发送SIGINT时就直接退出了。
这种设计是早期UNIX的遗留行为,目的是让开发者手动决定是否重新注册信号处理逻辑,但它的行为在不同系统中可能存在差异,属于“不可靠信号”的范畴。
解决办法
方法1:在处理函数内重新注册信号
在handler2内部再次调用signal,重新绑定处理函数,确保下次收到信号时仍能触发自定义逻辑:
void handler2(int sig) { int olderrno = errno; // 重新注册SIGINT的处理函数 if (signal(SIGINT, handler2) == SIG_ERR) unix_error("signal re-registration error"); Sio_puts("Handler in "); Sio_putl(getpid()); Sio_puts("\n"); errno = olderrno; }
注意:这种方式存在竞态条件——如果在重新注册完成前再次收到SIGINT,仍会触发默认终止行为。
方法2:使用标准可靠的sigaction函数
sigaction是POSIX标准定义的信号处理接口,行为明确且跨平台一致,默认不会自动重置处理动作。替换signal函数即可解决问题:
#include "csapp.h" void handler2(int sig) { int olderrno = errno; Sio_puts("Handler in "); Sio_putl(getpid()); Sio_puts("\n"); errno = olderrno; } int main() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler2; // 可选:添加SA_RESTART让被信号中断的系统调用(如Sleep)自动重启 // sa.sa_flags = SA_RESTART; if (sigaction(SIGINT, &sa, NULL) == -1) unix_error("sigaction error"); while (1) { printf("Parent %d\n", (int)getpid()); Sleep(5); } return 0; }
推荐使用这种方式,它是现代Linux系统中处理信号的标准方案,避免了传统signal的行为不确定性。
内容的提问来源于stack exchange,提问作者elivon
相关产品推荐
相关产品推荐

