为何C程序接收SIGALRM信号后直接退出?如何修复?
问题分析与修复
程序退出的原因
当SIGALRM信号触发时,正在阻塞等待输入的getchar()系统调用会被信号中断,返回-1。而EOF在标准IO中的定义就是-1,因此循环里的if(ch == 'q' || ch == EOF)条件被触发,直接跳出循环导致程序退出。
修复方案
方案一:让系统调用自动重启
修改sigaction的sa_flags,添加SA_RESTART标志。这个标志会让被信号中断的阻塞系统调用自动重新执行,而不是返回错误。修改后的代码片段:
struct sigaction sa; sa.sa_handler = thread_signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; // 新增该标志 sigaction(SIGALRM, &sa, NULL);
方案二:手动处理中断错误
在循环中检查getchar()返回EOF是否是因为信号中断导致的。需要引入<errno.h>头文件,当系统调用被信号中断时,errno会被设置为EINTR,此时我们可以忽略这个错误,继续等待输入。修改后的循环代码:
#include <errno.h> // 新增头文件 // ... 其余代码不变 ... while (1) { errno = 0; int ch = getchar(); if (ch == 'q' || ch == EOF) { // 仅当不是信号中断导致的EOF时才退出 if (errno != EINTR) { break; } } }
额外提示
- 信号处理函数中使用
printf存在风险:printf不属于POSIX定义的信号安全函数,在信号处理中调用可能引发竞态或未定义行为。建议改用write系统调用替代,示例:write(STDOUT_FILENO, "time run out!!!\n", 16); - 如果需要定时器重复触发,将
timer.it_interval设置为非0值即可,比如timer.it_interval.tv_sec = 5;,这样定时器会每隔5秒触发一次。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

