您的位置:首页 > 运维架构 > Linux

linux:进程中信号的“3种状态 And 3张表”

2017-06-14 19:04 288 查看

高能预警

本文主要介绍了信号在进程pcb中的表示方法并用代码验证其真实性。

主要内容有:

1.信号在进程中的表示方法:3种状态—3张表

2.对上述方法进行代码验证,包括:

信号集(sigset_t)和信号屏蔽字(Signal Mask)及信号集操作函数的介绍

代码验证(pending表)

————>全文阅读大概需要5min(我发四)<————

3种状态 And 3张表

在博主上篇博文中降到进程收到信号后,其可选的处理动作有以下三种:

1.忽略此信号。

2.执⾏行该信号的默认处理动作(终止该信号)。

3.提供⼀个信号处理函数(自定义动作),要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号。

欢迎大家围观:linux信号基本概念及如何产生信号

而这3种处理动作属于信号的第3种状态信号递达(进程对信号的实际处理动作)

很明显,信号递达是信号已经被进程接收时的状态。

而信号在没有发给进程之前,有两种状态:

第1种:信号阻塞(被阻塞的信号产生时将一直保持在未决状态,直到进程解除对此信号的阻塞, 才执⾏递达的动作)

第2种:信号未决(信号从产生到递达之间的状态)

一定要区分阻塞和忽略的区别:

1.忽略是进程对信号的一种处理方式,它属于信号递达状态。而阻塞是跟信号递达同级的概念。

2.只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

3种状态说完了,下面我们来看信号在进程pcb中是如何存储的,具体来说,就是3张表:



这3张表分别对应3种状态:

信号阻塞(block)

信号未决(pending)

信号递达—自定义捕捉函数(handler)

其中,前两张表都是位图(BitSet)来存储的。信号被阻塞就将相应位置1,否则置0。而pending表中,若置1则表示信号存在,0则相反。换句话说,pending表中的数据是判断信号是否存在的唯一依据。

此外,上图中还有3个例子,结合上边的概念就可以知道:

SIGALRM信号未阻塞也未产生过,但当它递达时就会执行默认处理动作。

SIGINT信号产生过,但已被阻塞。所以暂时不能递达。虽然它的处理动作是忽略。但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。

SIGQUIT信号未产生过,一旦产⽣将被阻塞,它的处理动作是用户自定义的捕捉函数handler。

还有一个问题:如果在进程解除对某信号的阻塞之前这种信号产生多次,将如何处理?

POSIX.1标准允许系统递送某信号一次或多次。Linux是这样实现的:常规信号(1-31)在递达之前产⽣生多次只计一次。而实时信号(34-64)在递达之前产生多次可以依次放在一个队列里。

信号集(sigset_t)和信号屏蔽字(Signal Mask)

在上图中,未决和阻塞标志都可以用相同的数据结构(位图)存储。所以当然可以用同一数据类型来表示,这就是sigset_t.

sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态。在阻塞信号集其含义是该信号是否被阻塞;在未决信号集中就代表该信号是否处于未决状态。

阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。


既然未决和阻塞状态都是用位图来表示的,那么能不能用移位操作来改变信号状态呢?,当然是——不行的。系统对于信号集有特定的信号集操作函数,所以不能用移位操作。只能调用这些操作函数来改变信号状态。那么接下来就来看看系统中有哪些信号集操作函数吧:



注:在使用sigset_t类型的变量之前,⼀定要调用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。

此外,系统还提供了信号屏蔽字(block表)的操作函数



其中:

1.如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。

2.如果set是非空指 针,则更改进程的信号屏蔽字,参数how指示如何更改。

3.如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。

假设当前的信号屏蔽字为mask,下表说明了how参数的可选值:



注:如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。

还有读取未决信号集(pending表)的函数



因为信号存不存在是客观事实,所以系统没有必要提供对pending表的设置接口。

Code

了解了信号集和信号屏蔽字的概念和信号集的各种操作函数。现在我们来编写代码测试一下信号的存储是否真如上边所说。

step1:屏蔽2号信号后,再使其变为未决状态,观察信号集数据由0变1

代码:





执行效果:



step2:解除2号信号的阻塞状态,使其抵达。捕捉到2号信号后,信号集数据又从1变0,变为以前的状态。再次crtl+c后,就不会发生1中的变化了。

代码:



执行效果:



The End

信号系列文还有最后一篇“信号的捕捉”,博主后续会更新。敬请期待。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: