sigaction结构体详解
sigaction
结构体详解
sigaction
是 Unix/Linux 系统编程中用于管理信号处理行为的核心数据结构。它通过 sigaction()
系统调用设置信号处理方式,比传统的 signal()
函数更灵活、安全。
结构体定义(POSIX 标准)
#include <signal.h>struct sigaction {void (*sa_handler)(int); // 基础信号处理函数void (*sa_sigaction)(int, siginfo_t *, void *); // 高级信号处理函数sigset_t sa_mask; // 执行处理函数期间阻塞的信号集int sa_flags; // 控制标志位void (*sa_restorer)(void); // 已废弃,勿用
};
成员详解
-
sa_handler
- 类型:
void (*)(int)
- 作用: 指向传统信号处理函数(接受信号编号
int
作为参数)。 - 特殊值:
SIG_IGN
: 忽略信号SIG_DFL
: 恢复默认行为
- 类型:
-
sa_sigaction
- 类型:
void (*)(int, siginfo_t *, void *)
- 作用: 高级信号处理函数(需设置
SA_SIGINFO
标志)。 - 参数:
int signo
: 信号编号siginfo_t *info
: 携带额外信号信息(来源进程、错误码等)void *context
: 进程上下文(寄存器状态等)
- 类型:
-
sa_mask
- 类型:
sigset_t
(信号集) - 作用: 在执行信号处理函数期间,阻塞指定的信号集(防止嵌套中断)。
- 注意:
- 当前处理的信号自动被阻塞(除非设置
SA_NODEFER
)。 - 使用
sigemptyset()
、sigaddset()
等操作信号集。
- 当前处理的信号自动被阻塞(除非设置
- 类型:
-
sa_flags
- 关键标志位(通过位掩码
|
组合):标志 作用 SA_SIGINFO
使用 sa_sigaction
(而非sa_handler
)获取详细信息SA_RESTART
被信号中断的系统调用自动重启 SA_NODEFER
执行处理函数时不自动阻塞当前信号(允许递归处理) SA_RESETHAND
处理完成后将信号恢复为默认行为(类似传统 signal()
的一次性特性)SA_ONSTACK
使用备选信号栈(通过 sigaltstack
设置)
- 关键标志位(通过位掩码
-
sa_restorer
- 已废弃,现代系统无需使用。
关键机制说明
-
信号阻塞规则
- 当信号处理函数执行时:
- 当前信号自动加入阻塞集(除非
SA_NODEFER
)。 sa_mask
中指定的信号被阻塞。
- 当前信号自动加入阻塞集(除非
- 处理完成后,阻塞集恢复为调用前的状态。
- 当信号处理函数执行时:
-
sa_handler
vssa_sigaction
- 两者共享同一存储空间,只能选其一。
- 若
sa_flags
包含SA_SIGINFO
,则使用sa_sigaction
;否则使用sa_handler
。
-
siginfo_t
结构示例typedef struct {int si_signo; // 信号编号int si_code; // 信号来源(如 USER/KILL/SEGV)pid_t si_pid; // 发送信号的进程IDuid_t si_uid; // 发送者的真实用户IDvoid *si_addr; // 引发故障的内存地址(如 SIGSEGV)int si_status; // 退出状态(SIGCHLD 时有效)// ... 其他扩展字段 } siginfo_t;
使用示例
1. 基础用法(sa_handler
)
#include <signal.h>
#include <stdio.h>
#include <unistd.h>void handler(int sig) {printf("Received SIGINT!\n");
}int main() {struct sigaction sa;sa.sa_handler = handler; // 设置处理函数sigemptyset(&sa.sa_mask); // 清空调用时阻塞的信号集sa.sa_flags = 0; // 无特殊标志sigaction(SIGINT, &sa, NULL); // 注册 SIGINTwhile(1) pause(); // 等待信号return 0;
}
2. 高级用法(sa_sigaction
)
#include <signal.h>
#include <stdio.h>void advanced_handler(int sig, siginfo_t *info, void *ucontext) {printf("Signal %d from PID: %d, UID: %d\n", sig, info->si_pid, info->si_uid);
}int main() {struct sigaction sa;sa.sa_sigaction = advanced_handler;sigemptyset(&sa.sa_mask);sa.sa_flags = SA_SIGINFO; // 启用高级处理sigaction(SIGINT, &sa, NULL);while(1) pause();return 0;
}
最佳实践
-
优先选择
sigaction
而非signal
sigaction
行为明确,可跨平台移植(signal()
在不同系统实现不一致)。
-
始终初始化
sa_mask
- 使用
sigemptyset()
或sigfillset()
显式设置阻塞集,避免未定义行为。
- 使用
-
需要额外信息时用
SA_SIGINFO
- 例如获取信号发送者的 PID、内存错误地址等。
-
考虑
SA_RESTART
- 对需要自动重启的系统调用(如
read()
、write()
)更友好。
- 对需要自动重启的系统调用(如
-
避免使用
SA_RESETHAND
- 可能导致信号处理重置为默认行为,引发意外结果(如程序退出)。