在C语言开发中,信号处理是用来响应异步事件的一种机制,比如用户按下Ctrl+C、子进程结束或者程序发生段错误,系统都会向进程发送信号。C语言标准库和POSIX接口提供了一组函数,让我们可以捕获这些信号并做自定义处理。

信号的基本概念
信号是操作系统向进程发送的软件中断。每个信号都有一个编号和默认行为,例如终止进程、忽略或者产生核心转储。常见信号有:
- SIGINT:终端中断,通常是Ctrl+C
- SIGTERM:终止请求,可被捕获
- SIGSEGV:非法内存访问
- SIGCHLD:子进程状态改变
使用signal函数实现信号处理
最简单的方式是调用标准库中的 signal() 函数,它可以为指定信号注册一个处理函数。函数原型为:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
// 自定义SIGINT处理函数
void handle_sigint(int sig) {
printf("捕获到信号 %d,程序即将退出n", sig);
exit(0);
}
int main() {
// 注册信号处理函数
signal(SIGINT, handle_sigint);
while (1) {
// 模拟工作
printf("运行中,按Ctrl+C测试n");
sleep(1);
}
return 0;
}
上面的代码把SIGINT绑定到handle_sigint,当用户按下Ctrl+C时,不会直接终止,而是先打印信息再退出。
更可靠的sigaction函数
在实际项目中,更推荐使用 sigaction() 函数,它比signal更可控,且在不同系统上行为一致。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void handle_term(int sig) {
printf("收到SIGTERM,干净退出n");
exit(0);
}
int main() {
struct sigaction sa;
sa.sa_handler = handle_term;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
// 为SIGTERM注册处理
sigaction(SIGTERM, &sa, NULL);
while (1) {
sleep(1);
}
return 0;
}
其他相关函数
除了signal和sigaction,还有几个常用函数:
| 函数 | 作用 |
|---|---|
| raise() | 向当前进程发送信号 |
| kill() | 向指定进程发送信号 |
| pause() | 挂起进程直到收到信号 |
| sigprocmask() | 阻塞或解除阻塞信号 |
注意事项
在信号处理函数里,只能调用异步信号安全的函数,比如write、_exit,不要使用printf或malloc,否则可能导致程序不稳定。另外,如果处理逻辑复杂,通常的做法是在处理函数里设置一个全局标记,在主循环里检查标记。
信号处理是编写健壮C语言服务程序的重要基础,掌握signal与sigaction的区别和用法非常关键。