信号三大阶段之储存信号

目录

一、 信号三大阶段

二、信号储存相关概念

三、 理解概念

四、信号储存原理

五、信号集操作函数


一、 信号三大阶段

二、信号储存相关概念

  1. 实际执行信号的过程被称为信号递达(Delivery)。
  2. 信号从产生到递达之间的状态被称为信号未决(Pending)。
  3. 进程可以选择阻塞(Block)某个信号。
  4. 被阻塞的信号产生时将保存在未决状态,直到进程解除对此信号的阻塞,才会执行递达动作。
  5. 注意:阻塞和忽略是不同的,信号被阻塞就不会递达,而忽略是递达之后可以选择的一种执行方式。

三、 理解概念

理解一下过程:

一般来说,操作系统向进程写入一个信号,信号先是被阻塞(假设设置了对这个信号的阻塞)什么都不会做;接着进程解除了对该信号的阻塞,信号进入未决状态(就是进程执行相关任务前的这段时间);进程到了合适的时间,就会执行信号对应的相关操作(也就是信号递达)。

简单理解就是:写入信号——看是否被阻塞——解除阻塞进入未决状态——进程执行相关操作。

详细理解一下每个步骤:

1、假设你在读书的时候你很喜欢一个老师,老师在课上布置了一个课后作业,你把这个作业先记录到了小本子上面,然后回家后就立马写作业

这个例子话黑线部分就分别对应了信号未决状态信号递达状态

2、假设你一般喜欢另一个老师,但是他不怎么检查作业,一天上课它布置了一个课后作业,你也拿小本子记了下来,除了记在作业那一页,你还记在里另一页上表示这个作业不急着写,因为反正老师也不检查,你就想只完成例子一的作业不就行了。但是有一天这个老师说明天要检查作业,你就把它从不急着写那里划掉了然后晚上将这个作业完成

这个例子中的黑体分别对应了信号阻塞信号未决信号递达状态。

四、信号储存原理

 信号是被存放在进程里的,更具体的说,是存放在task_struct里的——用于管理进程的结构体。除了实时信号我们用的到的信号就31个,那么我们用一个int类型的数据就可以把一个信号储存起来——也就是位图结构,位图的位数表示几号信号,某一位上的0、1表示是否有接收到该信号。————这就对应了task_struct里的pending,这个几十用于存放信号的容器。

00000000000000000000000000000011 

这个就表示该进程接收到了12号信号。

同理的我们也可以用相同的结构,存放一些数据来表示一个信号是否被阻塞————与之对应的是block

00000000000000000000000000000001 

这里就表示1号进程被阻塞了。

这两个都是用sigset_t的数据类型。阻塞信号集也被称之为当前进程的信号屏蔽字,这里的屏蔽应该理解成阻塞而不是忽略。

还剩下一个非常关键的东西:handler数组。我们有31个信号,这个数组就有31个元素,分别对应接受到每个信号时,我们分别需要做什么。这也就是为什么一个进程会认识这些信号,因为收到信号要做什么都是早就被设置好的。

 

五、信号集操作函数

sigset_t 是一个操作系统内核中的数据结构,用于表示信号集。在使用信号相关的系统调用时,会涉及到对 sigset_t 进行操作,例如添加、删除、屏蔽、解除屏蔽等。这些操作需要使用一些特定的函数来实现,因为这些函数通常会与操作系统内核进行交互。此外,操作 sigset_t 需要涉及到底层的机制,例如信号处理器、信号屏蔽、信号队列等,这些机制通常需要由操作系统内核来管理。因此,只能使用函数来操作 sigset_t。

上面这段话总而言之就是:要对sigset_t进行操作只能通过一下几个函数:

#include <signal.h>
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);
  1. 函数sigemptysetchushihuaset所指向的信号集,使其所有bit位置0,表示该信号不包含任何有效信号。
  2. 函数sigfillset初始化set所指的信号集,使其中所有信号对应bit位置表示该信号集的有效信号集包括系统支持的所有信号。
  3. 注意,在使用sigset_t类型变量之前,一定要调用sigemptyset或者sigfill做初始化,使信号处于确定的状态,初始化sigset_t变量后就可以在调用sigaddset和sigdelset在该信号添加或者删除某种有效信号。
  4. 函数sigaddset,参数signo表示要在set信号集中添加哪个信号。
  5. 这四个函数都是成功返回0,失败返回-1.sigismenber是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错则返回-1。

上面这些函数都是对sigset_t信号集操作的,但是我要怎么阻塞或则读取信号呢?如果不能实现这个功能的话,那岂不是上面这些函数也没什么用呀。

sigprocmask函数,调用这个函数可以读取或则更改进程的信号屏蔽字(阻塞信号集)。

 

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
//返回值:成功返回0,失败返回-1
  1. 参数set就是我们上面用那些函数产生的一个sigset_t信号集。
  2. 参数oset是一个输出型参数,就是oldset的缩写,因为我们可能会对进程内原有的信号集进行修改,所以我们可以保留进程内原有的set,将它写入oset。
  3. 第一个参数how就是你希望执行的操作模式有一下三种:

 

函数sigpending()

#include <signal.h>
sigpending(&sigset_t set);
//读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。 

实操例子:

运行结果:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一周学八天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值