为何两次发送SIGINT信号(Ctrl-C)后信号处理器失效?
关于Linux下C语言信号处理器的疑问
我在Linux系统中学习编写C语言信号处理器,写了如下代码:
#include<stdio.h> #include<signal.h> #include<unistd.h> void sig_handler(int signum){ //Return type of the handler function should be void printf("\nInside handler function\n"); } int main(){ signal(SIGINT,sig_handler); // Register signal handler for(int i=1;;i++){ //Infinite loop printf("%d : Inside main function\n",i); sleep(1); // Delay for 1 second } return 0; }
疑问:为什么按下Ctrl+C两次后程序就停止了?按道理每次按下Ctrl+C都应该触发信号处理器,程序应该一直运行才对?
实际运行时,只有第一次Ctrl+C触发了信号处理器,第二次直接终止程序,输出如下:
1 : Inside main function 2 : Inside main function 3 : Inside main function 4 : Inside main function ^C Inside handler function 5 : Inside main function 6 : Inside main function 7 : Inside main function 8 : Inside main function 9 : Inside main function 10 : Inside main function ^C
原因分析
这是因为传统signal()函数的行为在不同系统实现中存在不一致性,在Linux的常见实现里,当信号被处理完成后,该信号的处理方式会被自动重置为默认行为(即SIG_DFL,直接终止进程)。
具体流程:
- 第一次按下Ctrl+C触发
SIGINT信号,自定义处理器sig_handler被执行,但执行结束后,SIGINT的处理逻辑被恢复为默认的终止操作。 - 第二次按下Ctrl+C时,系统使用默认处理逻辑,直接终止了程序。
解决方法
方法1:使用标准可靠的sigaction()函数
sigaction()是POSIX标准定义的信号处理接口,行为稳定可预测,默认不会在信号处理后重置处理方式。修改后的代码如下:
#include<stdio.h> #include<signal.h> #include<unistd.h> void sig_handler(int signum){ printf("\nInside handler function\n"); } int main(){ struct sigaction sa; sa.sa_handler = sig_handler; sigemptyset(&sa.sa_mask); // 处理信号时不阻塞其他信号 sa.sa_flags = 0; // 保持默认行为,不自动重置处理器 sigaction(SIGINT, &sa, NULL); // 注册信号处理器 for(int i=1;;i++){ printf("%d : Inside main function\n",i); sleep(1); } return 0; }
方法2:在信号处理器内重新注册
如果坚持使用signal(),可以在自定义处理器函数末尾重新注册一次信号处理逻辑,确保下次信号到来时依然调用自定义处理器:
#include<stdio.h> #include<signal.h> #include<unistd.h> void sig_handler(int signum){ printf("\nInside handler function\n"); signal(SIGINT, sig_handler); // 重新注册信号处理器 } int main(){ signal(SIGINT, sig_handler); for(int i=1;;i++){ printf("%d : Inside main function\n",i); sleep(1); } return 0; }
两种方法都能实现每次按下Ctrl+C都触发自定义处理器,程序不会被终止。
内容的提问来源于stack exchange,提问作者JobHunter69
相关产品推荐
相关产品推荐

