题目
编写一个捕获SIGINT信号的简单程序
信息
- 类型:问答
- 难度:⭐
考点
信号处理基本概念,signal函数使用,信号处理函数编写
快速回答
实现步骤:
- 包含头文件
#include <signal.h> - 定义信号处理函数(如
void handler(int sig) { ... }) - 使用
signal(SIGINT, handler)注册处理函数 - 主函数中通过
while(1)保持程序运行
核心代码:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigint_handler(int sig) {
printf("Caught SIGINT!\n");
}
int main() {
signal(SIGINT, sigint_handler);
while(1) {
sleep(1);
}
return 0;
}
## 解析
1. 原理说明
信号是操作系统向进程发送的异步事件通知。当用户按下Ctrl+C时,终端会向前台进程组发送SIGINT信号(默认行为是终止进程)。通过注册自定义处理函数,可以改变信号的默认行为。
2. 完整代码示例
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
// 信号处理函数
void sigint_handler(int sig) {
// 注意:printf不是异步安全函数,实际应用应避免使用
printf("Caught SIGINT (Signal Number: %d)!\n", sig);
}
int main() {
// 注册信号处理函数
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
perror("signal registration failed");
return 1;
}
printf("Press Ctrl+C to test. PID: %d\n", getpid());
// 保持程序运行
while(1) {
sleep(1); // 避免CPU空转
}
return 0;
}3. 关键点解析
- signal函数:
signal(int sig, void (*handler)(int))用于注册信号处理函数,第一个参数是信号编号(如SIGINT),第二个是函数指针 - 处理函数参数:信号处理函数接收一个整数参数,表示信号编号(
SIGINT值为2) - 程序保持运行:
while(1)循环使程序持续运行以便测试,配合sleep减少资源占用
4. 最佳实践
- 错误检查:始终检查
signal()返回值(可能返回SIG_ERR) - 异步安全函数:实际项目中应使用
write代替printf(printf非线程安全) - 信号重置:某些系统在信号触发后会重置为默认行为,需在处理函数中重新注册
5. 常见错误
- ❌ 忘记包含
signal.h头文件 - ❌ 处理函数签名错误(必须为
void func(int)) - ❌ 使用
printf等非异步安全函数导致未定义行为 - ❌ 主线程无等待逻辑导致程序立即退出
6. 扩展知识
- 信号列表:
SIGTERM(终止请求)、SIGKILL(强制终止,不可捕获)、SIGSEGV(段错误) - 更现代的方法:推荐使用
sigaction替代signal(提供更精确的控制) - 信号屏蔽:通过
sigprocmask阻塞信号,防止关键代码段被中断 - 多线程信号:在多线程程序中,信号处理是进程级别的,需特别设计