未决信号集和阻塞信号集的关系
阻塞信号集是当前进程要阻塞的信号的集合,未决信号集是当前进程中还处于未决状态的信号的集合,这两个集合存储在内核的PCB中。
- 下面以SIGINT为例说明信号未决信号集和阻塞信号集的关系:
- 当进程收到一个SIGINT信号(信号编号为2),首先这个信号会保存在未决信号集合中,此时对应的2号编号的这个位置上置为1,表示处于未决状态;在这个信号需要被处理之前首先要在阻塞信号集中的编号为2的位置上去检查该值是否为1:
- 如果为1,表示SIGNIT信号被当前进程阻塞了,这个信号暂时不被处理,所以未决信号集 上该位置上的值保持为1,表示该信号处于未决状态;
- 如果为0,表示SIGINT信号没有被当前进程阻塞,这个信号需要被处理,内核会对SIGINT信号进行处理(执行默认动作,忽略或者执行用户自定义的信号处理函数),并将未决信号集中编号为2的位置上将1变为0,表示该信号已经处理了,这个时间非常短暂,用户感知不到。
- 当SIGINT信号从阻塞信号集中解除阻塞之后,该信号就会被处理。
信号集相关函数
- int sigemptyset(sigset_t *set);
函数说明:将某个信号集清0
函数返回值:成功:0;失败:-1,设置errno
- int sigfillset(sigset_t *set);
函数说明:将某个信号集置1
函数返回值:成功:0;失败:-1,设置errno
- int sigaddset(sigset_t *set, int signum);
函数说明:将某个信号加入信号集合中
函数返回值:成功:0;失败:-1,设置errno
- int sigdelset(sigset_t *set, int signum);
函数说明:将某信号从信号清出信号集
函数返回值:成功:0;失败:-1,设置errno
- int sigismember(const sigset_t *set, int signum);
函数说明:判断某个信号是否在信号集中
函数返回值:在:1;不在:0;出错:-1,设置errno
- sigprocmask函数
函数说明:用来屏蔽信号、解除屏蔽也使用该函数。其本质,读
取或修改进程控制块中的信号屏蔽字(阻塞信号集)。
特别注意,屏蔽信号只是将信号处理延后执行(延至解除屏蔽);而忽略表示将信号丢弃处理。
函数原型:int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
函数返回值:成功:0;失败:-1,设置errno
函数参数:how参数取值:假设当前的信号屏蔽字为mask
SIG_BLOCK: 当how设置为此值,set表示需要屏蔽的信号。
SIG_UNBLOCK: 当how设置为此,set表示需要解除屏蔽的信号。
set:传入参数,是一个自定义信号集合。由参数how来指示如何修改当前信号屏蔽字
oldset:传出参数,保存旧的信号屏蔽字。
- sigpending函数
函数原型:int sigpending(sigset_t *set);
函数说明:读取当前进程的未决信号集函数参数:set传出参数
函数返回值:成功:0;失败:-1,设置errno
练习:编写程序,设置阻塞信号集并把所有常规信号的未决状态打印至屏幕(以二号和三号信号为例)
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
using namespace std;
//信号处理函数
void sighandler(int signo)
{
cout << "signo==[" << signo << "]" << endl;
}
int main()
{
//注册SIGINT和SIGQUIT的信号处理函数
signal(SIGINT, sighandler);//2 ctrl+c
signal(SIGQUIT, sighandler);//3 ctrl+/
//定义sigset_t类型的变量
sigset_t pending, mask, oldmask;
//初始化
sigemptyset(&pending);
sigemptyset(&mask);
sigemptyset(&oldmask);
//将SIGINT和SIGQUIT加入到阻塞信号集中
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
//将mask中的SIGINT和SIGQUIT信号加入到阻塞信号集中
//sigprocmask(SIG_BLOCK, &mask, NULL);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
int i = 1;
int k = 1;
while(1)
{
//获取未决信号集
sigpending(&pending);
for(i=1; i<32; i++)
{
//判断某个信号是否在集合中
if(sigismember(&pending, i)==1)
{
cout << "1";
}
else
{
cout << "0";
}
}
cout << endl;
if(k++%10==0)
{
//从阻塞信号集中解除对SIGINT和SIGQUIT的阻塞
//sigprocmask(SIG_UNBLOCK, &mask, NULL);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
else
{
sigprocmask(SIG_BLOCK, &mask, NULL);
}
sleep(1);
}
return 0;
}
结果如下:
产生信号后就被阻塞,然后被打印出来1