sigaction 完全指南:Linux信号处理的终极武器
为什么需要 sigaction?
传统的 signal 函数存在多个问题:行为因系统而异、无法控制处理期间阻塞的信号、不能获取信号来源信息。sigaction 解决了这些问题,提供了更强大、更可控的信号管理机制。
核心数据结构
structsigaction {void (*sa_handler)(int); // 简单处理函数void (*sa_sigaction)(int, siginfo_t *, void *); // 详细处理函数sigset_t sa_mask; // 处理期间要阻塞的信号int sa_flags; // 行为控制标志};
关键字段说明
- **
sa_handler**:经典的单参数处理函数 - **
sa_sigaction**:三参数处理函数,可获取详细信息(需设置SA_SIGINFO) - **
sa_mask**:指定处理当前信号时,哪些信号应该被阻塞 - **
sa_flags**:常用标志包括SA_RESTART(自动重启中断的系统调用)、SA_SIGINFO(使用三参数函数)
函数原型
intsigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
- **
signum**:要处理的信号(如SIGINT) - **
oldact**:保存旧的信号处理行为(可恢复原状)
实战示例
示例1:基础用法(替换signal)
#include<stdio.h>#include<signal.h>#include<string.h>#include<unistd.h>voidhandler(int sig){ write(1, "收到SIGINT\n", 11);}intmain(){structsigactionsa;memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; // 系统调用自动重启 sigaction(SIGINT, &sa, NULL);while(1) pause();return0;}
示例2:使用oldact保存和恢复
structsigactionnew_act, old_act;// 设置新处理程序,保存旧的new_act.sa_handler = my_handler;sigemptyset(&new_act.sa_mask);sigaction(SIGINT, &new_act, &old_act);// 执行关键代码...// 恢复原来的处理程序sigaction(SIGINT, &old_act, NULL);
示例3:使用sa_mask阻塞其他信号
voidslow_handler(int sig){printf("开始处理,期间阻塞SIGTERM\n"); sleep(5); // 此时SIGTERM被阻塞,不会打断处理printf("处理完成\n");}intmain(){structsigactionsa; sa.sa_handler = slow_handler; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGTERM); // 处理SIGINT时阻塞SIGTERM sa.sa_flags = 0; sigaction(SIGINT, &sa, NULL);// ...}
示例4:获取信号详细信息
voidinfo_handler(int sig, siginfo_t *info, void *context){printf("信号来源PID: %d\n", info->si_pid);printf("发送者UID: %d\n", info->si_uid);printf("附加数据: %d\n", info->si_value.sival_int);}intmain(){structsigactionsa; sa.sa_sigaction = info_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; // 必须设置此标志 sigaction(SIGINT, &sa, NULL);// ...}
与signal的对比
最佳实践
- 初始化所有字段:使用
memset和sigemptyset - 信号处理函数要简单:只调用异步信号安全函数(如
write) - 使用
volatile sig_atomic_t与主程序通信volatilesig_atomic_t flag = 0;voidhandler(int sig){ flag = 1; }
常见陷阱
- **忘记初始化
sa_mask**:导致随机信号被阻塞 - **在信号处理函数中调用
printf**:不是异步安全,可能死锁
总结
sigaction 不仅仅是多了一个 oldact,它提供了完整的信号控制体系:
- **
sa_flags**:定制行为(自动重启、获取详细信息)
掌握 sigaction,你就能真正掌控Linux信号处理的每一个细节。