1. Linux信号机制基础概念
信号是Linux系统中进程间通信的一种基本机制,它允许一个进程向另一个进程发送异步通知。当我们在终端按下Ctrl+C时,实际上就是向当前前台进程发送了一个SIGINT信号。信号机制的设计初衷是为了处理异常情况和进程控制,但现在已经发展成为一种通用的进程间通信手段。
信号的处理涉及三个核心概念:信号产生、信号递送和信号处理。信号产生是指某个事件触发了信号(比如硬件异常、终端交互或kill命令);信号递送是指内核将信号传递给目标进程;信号处理则是进程对接收到的信号采取的动作(忽略、捕获或执行默认动作)。
注意:信号是异步的,这意味着进程在任何时候都可能收到信号,因此信号处理程序需要特别小心地编写,避免竞态条件。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 信号集与信号阻塞机制
2.1 信号集数据结构
在Linux中,信号集(sigset_t)是用来表示一组信号的数据结构。它本质上是一个位掩码,每个比特位对应一个信号编号。例如,32位系统上的sigset_t通常是一个32位整数,可以表示信号1到31(信号0是保留的)。
c复制typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
我们可以使用以下函数操作信号集:
- sigemptyset() - 初始化空信号集
- sigfillset() - 初始化包含所有信号的信号集
- sigaddset() - 向信号集中添加信号
- sigdelset() - 从信号集中删除信号
- sigismember() - 测试信号是否在信号集中
2.2 信号阻塞原理
信号阻塞是指暂时阻止信号被递送到进程。每个进程都有一个信号掩码(signal mask),它定义了当前被阻塞的信号集。当信号被阻塞时,它不会被立即递送,而是保持为未决状态,直到解除阻塞。
阻塞信号的常见场景包括:
- 保护关键代码段不被信号中断
- 防止信号处理程序重入
- 实现原子性操作
c复制int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how参数可以是:
- SIG_BLOCK - 将set中的信号添加到当前阻塞信号集
- SIG_UNBLOCK - 从当前阻塞信号集中移除set中的信号
- SIG_SETMASK - 直接将当前阻塞信号集设置为set
3. 未决信号集详解
3.1 未决信号的概念
未决信号(pending signals)是指已经产生但尚未递送给进程的信号。造成信号未决的原因主要有两个:
- 信号当前被阻塞
- 信号正在排队等待处理(仅对实时信号有效)
内核为每个进程维护一个未决信号集,可以通过sigpending()函数获取:
c复制int sigpending(sigset_t *set);
3.2 未决信号的生命周期
一个信号从产生到最终处理经历了以下阶段:
- 信号产生(由硬件、软件或用户触发)
- 内核检查目标进程的信号掩码:
- 如果信号未被阻塞,立即递送
- 如果被阻塞,加入未决信号集
- 当信号被解除阻塞时:
- 对于标准信号(1-31),只保留一个实例
- 对于实时信号(34-64),所有排队的实例依次递送
重要提示:标准信号是不排队的,这意味着如果在信号被阻塞期间多次产生同一信号,解除阻塞后进程只会收到一次该信号。
4. 阻塞信号集与未决信号集的交互
4.1 两者的关系模型
阻塞信号集和未决信号集的关系可以用以下伪代码表示:
code复制if (信号产生) {
if (信号在阻塞信号集中) {
将信号加入未决信号集
} else {
立即递送信号
}
}
4.2 实际应用示例
考虑以下场景:我们希望在执行关键代码段时不被打断,可以这样实现:
c复制sigset_t new_mask, old_mask, pending_mask;
// 设置要阻塞的信号
sigemptyset(&new_mask);
sigaddset(&new_mask, SIGINT);
sigaddset(&new_mask, SIGTERM);
// 阻塞信号
sigprocmask(SIG_BLOCK, &new_mask, &old_mask);
// 关键代码段
do_critical_work();
// 检查是否有未决信号
sigpending(&pending_mask);
if (sigismember(&pending_mask, SIGINT)) {
printf("SIGINT is pending\n");
}
// 恢复原来的信号掩码
sigprocmask(SIG_SETMASK, &old_mask, NULL);
5. 高级信号处理技术
5.1 实时信号处理
实时信号(SIGRTMIN到SIGRTMAX)相比标准信号有几个重要区别:
- 支持排队,不会丢失
- 可以携带附加信息
- 有明确的优先级顺序
使用sigqueue()发送实时信号:
