【进程信号】五、信号集操作接口详解
文章目录
- Ⅰ. 操作sigset_t变量接口
- Ⅱ. sigprocmask(阻塞信号集)
- Ⅲ. sigpending(未决信号集)
- Ⅳ. 接口使用代码
- ⚜️sigaction(捕捉信号)
- Ⅴ. 测试sigaction的一些场景

Ⅰ. 操作sigset_t变量接口
还记得我们上面讲过的 sigset_t
类型吗,sigset_t
类型对于每种信号用一个 bit
表示 “有效” 或 “无效” 状态,至于这个类型内部如何存储这些 bit
则依赖于系统实现,从使用者的角度是不必关心的,因为不同的操作系统可能对 sigset_t
变量的定义不一样,有的可能是变量,有的可能是数组,有的可能是封装在结构体内等等。
使用者只能调用以下函数来操作 sigset_t
变量,而不应该对它的内部数据做任何解释,比如用 printf
直接打印 sigset_t
变量是没有意义的!
#include <signal.h>
int sigemptyset(sigset_t *set); // 将set给定的信号集初始化为0
int sigfillset(sigset_t *set); // 将set初始化为full,也就是初始化所有信号为1
int sigaddset (sigset_t *set, int signo); // 在set中添加signo信号
int sigdelset(sigset_t *set, int signo); // 在set中删除signo信号
int sigismember(const sigset_t *set, int signo); // 检测signo信号是否存在set中// 返回值:前四个函数都是成功返回0,失败返回-1。
// 而sigismember()是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。
sigemptyset()
初始化set
所指向的信号集,使其中所有信号的对应bit
清零,表示该信号集不包含任何有效信号。sigfifillset()
初始化set
所指向的信号集,使其中所有信号的对应bit
置为1
,表示该信号集的有效信号包括系统支持的所有信号。
💥💥注意:在使用 sigset_ t
类型的变量之前,一定要调用 sigemptyset()
或 sigfifillset()
做初始化,使信号集处于确定的状态。初始化 sigset_t
变量之后就可以再调用 sigaddset()
和 sigdelset()
在该信号集中添加或删除某种有效信号。
Ⅱ. sigprocmask(阻塞信号集)
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); // 作用:可以读取或更改进程的信号屏蔽字(阻塞信号集)
// 返回值:若成功则为0,若出错则为-1,并且设置错误码errno
- 如果
oldset
是非空指针,则读取进程的当前信号屏蔽字通过oldset
参数传出。 - 如果
set
是非空指针,则更改进程的信号屏蔽字,参数how
指示如何更改。 - 如果
oldset
和set
都是非空指针,则先将原来的信号屏蔽字备份到oldset
里,然后根据set
和how
参数更改信号屏蔽字。
假设当前的信号屏蔽字(阻塞信号集)为 mask
,下表说明了 how
参数的可选值:
如果调用 sigprocmask()
解除了对当前若干个未决信号的阻塞,则在 sigprocmask()
返回前,至少将其中一个信号递达。
Ⅲ. sigpending(未决信号集)
#include <signal.h>
int sigpending(sigset_t *set);// 作用:读取当前进程的未决信号集,通过set参数传出
// 返回值:若成功则为0,若出错则为-1,并且设置错误码errno
// 参数:set为要读取的信号集
这个相对 sigprocmask()
来说会更加简单一点,其仅仅 只能读取未决信号集而已,而无法进行修改!
Ⅳ. 接口使用代码
下面我们写一段代码,我们来通过上面这些接口达到这个目的:定义我们自己的 sigset_t
类型变量,并且通过添加信号、删除信号,然后我们将每次这个变量的状态也就是比特位都打印出来,观察一下变化:
#include <iostream>
#include <signal.h>
#include <vector>
#include <unistd.h>
using namespace std