1. 信号处理机制的 “三张表”
kill -l
:前 31 个信号为系统标准信号。
block
pending
handler
三张表保存在每个进程的进程控制块 —— pcb
中,它们分别对应了某一信号的阻塞状态、待处理状态以及处理方式。
-
block
:通过sigset_t
类型实现,是一个位字段集合,每一位对应一个信号;如果某一位被设置,则对应的信号会被阻塞;信号的阻塞状态 与 该信号是否被发送到进程 无关 。 -
pending
:与block
相同,通过sigset_t
类型实现,用于记录 已经发送给进程但未被处理 的信号。 -
handler
:函数指针数组,指向各个信号的处理方法(函数)。
2. 介绍几个信号处理的系统调用
-
sigemptyset
:用于初始化一个信号集为空,即将信号集中的所有信号位都清零。创建一个
sigset_t
类型的变量,在对该变量进行各种信号处理操作之前,先要使用 sigemptyset 对该变量初始化。
sigset_t sig;
sigemptyset(&sig); // 对 sig 初始化, success -> 0, fail -> -1
sigaddset
:用于在一个已存在的信号集中添加信号。
sigaddset(&sig, SIGINT); // success return 0, fail return -1
sigprocmask
:用于更改当前进程的信号掩码,简单来说即设置哪些信号被阻塞。
sigprocmask(int how, const sigset_t* signal, sigset_t* old_signal);
how 的处理方式, SIG_BLOCK
SIG_UNBLOCK
SIG_SETMASK
SIG_BLOCK : 设置新的信号掩码,同时保留旧的信号掩码
SIG_UNBLOCK : 取笑新信号掩码中的信号阻塞,并保留旧的信号掩码
SIG_SETMASK : 设置新的信号掩码,并丢弃旧的信号掩码
sigset_t oldsig;
sigemptyset(&oldsig);
sigprocmask(SIG_SETMASK, &sig, &oldsig);
sigpending
:用于获取当前进程中待处理的信号集。
sigset_t pending;
sigemptyset(&pending);
sigpending(&pending);
sigismember
:用于测试一个信号是否在一个信号集中,存在返回 1,否则返回 0。
sigismember(&pending, SIGINT);
3. demo —— 示范案例
demo 中主要完成以下四个动作:
- 屏蔽 2 号信号 —— SIGINT
- 获取当前进程的 pending 表
- 打印 pending 表
- 取消对 2 号信号的屏蔽
其中,2.
和 3.
是 “同时” 且 重复 进行的,意味着将出现这样一个现象:当前进程在接收 2 号信号之前,pending 表 2 号信号对应位置为 0;向当前进程发生 2 号信号后,pending 表 2 号信号位置被设置。
以及,取消对 SIGINT 的屏蔽后,2 号信号会被立即递达,进程结束。
1) 屏蔽 2 号信号
#include <iostream>
using namespace std;
#include <signal.h>
int main()
{
// 1. 屏蔽 2 号信号
sigset_t block;
sigset_t old_block;
sigemptyset(&block);
sigemptyset(&old_block);
sigaddset(&block, SIGINT