题目
如何捕获并处理SIGINT信号?
信息
- 类型:问答
- 难度:⭐
考点
信号概念,信号处理函数注册,基本信号处理
快速回答
在C程序中捕获SIGINT信号(Ctrl+C触发)的步骤:
- 包含头文件:
#include <signal.h> - 定义信号处理函数:
void handler(int sig) { ... } - 使用
signal(SIGINT, handler)注册处理函数 - 处理函数中应避免调用非异步安全函数
1. 信号处理原理
信号是操作系统向进程发送的异步事件通知。当用户按下Ctrl+C时,系统会向当前前台进程发送SIGINT信号(中断信号),默认行为是终止进程。通过注册自定义处理函数,可以改变信号的响应行为。
2. 代码示例
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
// 自定义信号处理函数
void sigint_handler(int sig) {
write(STDOUT_FILENO, "\nSIGINT received! Exiting...\n", 28);
exit(0); // 安全退出
}
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); // 保持程序运行
}
return 0;
}3. 关键点说明
- signal函数:
signal(int sig, void (*handler)(int))用于注册处理函数,第一个参数是信号编号,第二个是函数指针 - 处理函数要求:应尽量简短,避免调用
printf/malloc等非异步安全函数(本例使用write替代printf) - 退出方式:处理函数中调用
exit()而非return,确保进程终止
4. 最佳实践
- 使用
sigaction替代signal(更可靠,但本题要求简单) - 处理函数中仅设置标志位,在主循环中处理实际逻辑
- 对全局变量使用
volatile sig_atomic_t类型保证原子访问
5. 常见错误
- 在处理函数中调用不可重入函数(如
printf),可能导致死锁或崩溃 - 忽略返回值检查:
signal()失败时返回SIG_ERR - 长时间阻塞处理函数,影响其他信号响应
6. 扩展知识
- 常见信号:
SIGTERM(终止请求)、SIGKILL(强制终止,不可捕获)、SIGSEGV(段错误) - 高级机制:
sigprocmask阻塞信号、sigaction设置更精细的处理参数 - 信号来源:终端输入、硬件异常(如除零错误)、其他进程通过
kill()发送