signal.h
<signal.h> 提供信号处理机制,允许程序响应异步事件(如用户按 Ctrl+C、除零错误、非法内存访问等)。信号处理是操作系统层面的概念,C 标准定义了最小子集,平台通常扩展更多信号。
基本用法
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void handler(int sig)
{
printf("Caught signal %d\n", sig);
exit(0);
}
int main(void)
{
signal(SIGINT, handler); /* 注册 Ctrl+C 处理 */
printf("Press Ctrl+C...\n");
while (1) {
/* 等待信号 */
}
return 0;
}
标准信号
| 信号 | 含义 |
|---|---|
SIGABRT | 异常终止(abort) |
SIGFPE | 浮点异常(除零等) |
SIGILL | 非法指令 |
SIGINT | 中断(Ctrl+C) |
SIGSEGV | 段错误 |
SIGTERM | 终止请求 |
信号处理函数
/* 忽略信号 */
signal(SIGINT, SIG_IGN); /* 忽略 Ctrl+C */
/* 恢复默认处理 */
signal(SIGINT, SIG_DFL); /* 默认:终止程序 */
/* 自定义处理 */
signal(SIGINT, handler);
发送信号
#include <signal.h>
raise(SIGINT); /* 向自己发送 SIGINT */
信号处理限制
void handler(int sig)
{
/* 信号处理函数中: */
/* - 只能调用异步信号安全函数 */
/* - 不能调用 malloc、printf(标准未保证安全) */
/* - 不能修改非 volatile sig_atomic_t 变量 */
volatile static sig_atomic_t count = 0;
count++;
if (count >= 3) {
_exit(1); /* 异步信号安全 */
}
}
常见错误
信号处理中调用不安全函数:
void handler(int sig)
{
printf("Signal %d\n", sig); /* 危险:printf 可能不是信号安全的 */
malloc(100); /* 危险:可能死锁 */
}
非原子变量:
int flag = 0;
void handler(int sig)
{
flag = 1; /* 危险:非原子写入 */
}
/* 正确 */
volatile sig_atomic_t flag = 0;
最佳实践
- 信号处理函数尽量简单
- 只设置标志位,主循环处理
- 用
volatile sig_atomic_t传递信息 - 了解平台特定的信号安全函数
- 现代程序考虑用更高级的机制(如事件循环)