当前位置:首页>Linux>系统|sigaction 完全指南:Linux信号处理的终极武器

系统|sigaction 完全指南:Linux信号处理的终极武器

  • 2026-09-10 05:17:33
系统|sigaction 完全指南:Linux信号处理的终极武器

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)
  • **act**:新的信号处理行为
  • **oldact**:保存旧的信号处理行为(可恢复原状)
  • 返回值:成功0,失败-1

实战示例

示例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的对比

特性
signal
sigaction
保存旧处理程序
❌
✅ (oldact)
阻塞其他信号
❌
✅ (sa_mask)
控制中断系统调用
❌
✅ (SA_RESTART)
获取信号来源
❌
✅ (SA_SIGINFO)
行为可预测
❌
✅

最佳实践

  1. 始终使用sigaction而非signal
  2. 初始化所有字段:使用memset和sigemptyset
  3. 信号处理函数要简单:只调用异步信号安全函数(如write)
  4. 使用volatile sig_atomic_t与主程序通信
    volatilesig_atomic_t flag = 0;voidhandler(int sig){ flag = 1; }
  5. 考虑使用SA_RESTART简化编程

常见陷阱

  • **忘记初始化sa_mask**:导致随机信号被阻塞
  • **在信号处理函数中调用printf**:不是异步安全,可能死锁
  • 忽略EINTR错误:系统调用可能被信号中断

总结

sigaction 不仅仅是多了一个 oldact,它提供了完整的信号控制体系:

  • **oldact**:保存和恢复处理程序
  • **sa_mask**:精细控制信号屏蔽
  • **sa_flags**:定制行为(自动重启、获取详细信息)
  • **sa_sigaction**:获取发送者信息

掌握 sigaction,你就能真正掌控Linux信号处理的每一个细节。

最新文章

随机文章