行业知识
Linux-信号2
文章目录
- 前言
- 一、信号是如何保存的?
- int sigemptyset(sigset_t *set);
- int sigfillset(sigset_t *set);
- int sigaddset (sigset_t *set, int signo);
- int sigdelset(sigset_t *set, int signo);
- int sigismember(const sigset_t *set, int signo);
- int sigpending(sigset_t *set);
- int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
- 1.SIG_BLOCK
- 2.SIG_UNBLOCK
- 3.SIG_SETMASK
- 二、学习步骤
- 我们提出三个问题并对问题进行一一解答来进行我们的学习
- 问题1. 如果我们将一个***循环进程的所有信号都捕捉,是不是该进程无法被退出?
- 问题2. 如果我们将一个信号block阻塞,并发送对应信号,pending表的对应该信号bit位是不是由0置1?
- 问题3. 如果我们将一个***循环进程的所有信号都阻塞,是不是该进程也无法被退出?
- 1.解答问题1
- 2.解答问题2
- 3.解���问题3
前言
上节课我们学习了信号产生到处理过程的现象以及信号的捕捉,这节课主要学习信号的保存。
我们需要熟练使用以下函数
#include
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
int sigpending(sigset_t *set);
一、信号是如何保存的?
上节课我们说过,信号是在进程的PCB中存储 信号的位图,而实际上,可不止有一个表(位图)。
block信号集是用以保存被block阻塞的信号,一般被称为信号屏蔽字(阻塞信号集),pending信号集就是我们上节课所说的那个收到信号即相对位由0置1的位图,一般被称为未决信号集。
对于阻塞,这是提前预设好的,目的是为了让该进程屏蔽该信号,所以如果一个信号被阻塞,而又收到了该信号,虽然pending信号集由0置1,但是不进行delivery(信号递达:信号递达操作即信号的处理)操作。
而这两个信号集,在我们看来理解其实就是位图,但是OS将他们封装成了自定义类型sigset_t,通过这样的封装,对于我们用户就无法随心所欲地更改其信号集的数据,只能通过OS提供给我的系统接口函数。
现在来认识一下系统交给我们的一些接口函数。
int sigemptyset(sigset_t *set);
函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有
效信号。
成功返回0,出错返回-1
int sigfillset(sigset_t *set);
函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系
统支持的所有信号。
成功返回0,出错返回-1
int sigaddset (sigset_t *set, int signo);
函数sigaddset用于将set所指向的信号集的signo信号置位。
成功返回0,出错返回-1
int sigdelset(sigset_t *set, int signo);
函数sigdelset用于将set所指向的信号集的signo信号置零。
成功返回0,出错返回-1
int sigismember(const sigset_t *set, int signo);
函数sigismember用于判断set所指向信号集的signo信号是否为1。
是则返回1,否则为0。
int sigpending(sigset_t *set);
函数sigpending用于读取当前进程的未决信号集,通过set参数传出。
调用成功则返回0,出错则返回-1。
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
函数sigprocmask用于更改block信号集,参数how为选项,该函数提供三种选项
1.SIG_BLOCK
该选项是希望在目前的信号屏蔽字添加set信号集的有效信号,相当于mask=mask|set
2.SIG_UNBLOCK
该选项是希望在目前的信号屏蔽字去除set信号集的有效信号,相当于mask=mask&(~set)
3.SIG_SETMASK
该选项就比较暴力些,相当于mask=set
而参数oset为输出型参数,用于保存老信号集。
需要注意的,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的
状态。
二、学习步骤
我们提出三个问题并对问题进行一一解答来进行我们的学习
问题1. 如果我们将一个***循环进程的所有信号都捕捉,是不是该进程无法被退出?
问题2. 如果我们将一个信号block阻塞,并发送对应信号,pending表的对应该信号bit位是不是由0置1?
问题3. 如果我们将一个***循环进程的所有信号都阻塞,是不是该进程也无法被退出?
1.解答问题1
代码如下(示例):
#include#include#include#includevoid catchSig(int signum){ std::cout for(int i = 1; i signal(i,catchSig); } while(1) { std::cout for (int i = 1; i // 通过sigismember来打印我们的pending信号集 std::cout sigset_t set; sigset_t block; sigset_t oset; // 1.进行初始化 sigemptyset(&set); sigemptyset(&block); sigemptyset(&oset); // 2.阻塞2号信号 sigaddset(&block, 2); sigprocmask(SIG_BLOCK, &block, &oset); std::cout // 3.1 获取当前的未决信号集 sigpending(&set); ShowSet(set); sleep(1); } return 0;} for (int i = 1; i // 通过sigismember来打印我们的pending信号集 std::cout if ((signum != 19) &&(signum != 9) && signum sigset_t set; sigset_t block; sigset_t oset; // 1.进行初始化 sigemptyset(&set); sigemptyset(&block); sigemptyset(&oset); // 2.阻塞所有信号 for (int i = 1; i sigaddset(&block, i); } sigprocmask(SIG_SETMASK, &block, &oset); // 3.循环打印未决信号集 int count = 1; while (1) { // 3.1 获取当前的未决信号集 sigpending(&set); ShowSet(set); SendSig(count++); sleep(1); } return 0;}