linux信号详解
一、信号本质
信号是进程间异步事件通知机制,通过软中断实现。当内核检测到事件(如硬件异常、终端输入、软件条件)时,会向目标进程递送信号12。
二、前台/后台进程信号差异
特性 | 前台进程 | 后台进程 |
---|---|---|
信号接收 | 可接收终端信号(Ctrl+C/Z) | 需通过kill命令发送信号 |
控制终端 | 独占输入输出 | 输出重定向到日志文件 |
示例 | ./server | ./server & |
三、信号产生机制
(一)信号处理函数
-
signal()函数
头文件:#include <signal.h>
原型:void (*signal(int sig, void (*func)(int)))(int);
返回值:成功返回旧处理函数指针,失败返回SIG_ERR48 -
sigaction()函数
结构体定义:
(二)软件条件产生信号
函数 | 作用域 | 信号类型 | 典型用例 |
---|---|---|---|
kill() | 跨进程 | 任意信号 | kill(pid, SIGTERM) |
raise() | 当前进程 | 任意信号 | raise(SIGUSR1) |
abort() | 当前进程 | SIGABRT | 触发核心转储 |
alarm() | 定时器 | SIGALRM | alarm(10) 10秒后触发 |
四、信号保存与阻塞
-
内核数据结构
task_struct { sigset_t blocked; // 阻塞信号集 sigset_t pending; // 未决信号集 struct sigaction[]; // 处理函数数组 }
-
信号集操作函数组
sigset_t set; sigemptyset(&set); // 初始化空集 sigaddset(&set, SIGINT); // 添加信号 sigprocmask(SIG_BLOCK, &set, NULL); // 设置屏蔽
五、信号捕捉流程
- 进程执行系统调用进入内核态
- 内核检查未决信号并处理
- 执行用户注册的处理函数
- 通过sigreturn系统调用恢复上下文5354
// 典型处理函数模板 void handler(int sig) { // 仅使用异步安全函数 char msg[] = "Signal received\n"; write(STDERR_FILENO, msg, sizeof(msg)); _exit(1); // 直接退出避免非可重入问题 }
六、中断与执行态
中断类型 | 触发源 | 处理流程 |
---|---|---|
硬件中断 | CPU异常/外设 | 保存现场→调用中断服务例程 |
软件中断 | 系统调用(int 0x80) | 切换内核态执行服务 |
信号处理 | 内核信号队列 | 用户态与内核态多次切换 |
七、可重入函数规范
安全实践:
- 仅使用局部变量
- 不调用malloc/free等非可重入函数
- 使用volatile修饰共享标志位3738
volatile sig_atomic_t shutdown_flag; void handler(int sig) { shutdown_flag = 1; }