UNIX/LINUX信号基本概念释疑

来源:互联网 发布:c语言如何开根号 编辑:程序博客网 时间:2024/05/20 05:08

引出问题

可能很多人和我一样,在学习APUE第10章信号章节时存在很多疑惑,究其原因可能是APUE没有对信号的生命周期有个详细明了的解释导致的。本文是通过网上的文章整理而成,正确与否,还望批评指正!

什么是同步事件,什么又是异步事件

首先大致解释下什么是同步事件,什么是异步事件,他们本质的区别是什么?

信号的同步和异步产生

所谓信号,是操作系统提供给进程处理异步事件(asynchronous events)的一种方法。通俗点说,就是异步事件发生时,操作系统通过信号这个通知机制来告诉进程。信号在操作系统中是通过软件中断(software interrupts)来实现的,它与硬件中断(hardware interrupts)的相似之处就是打断了进程执行的正常流程。

那么进程能否预测信号到达的精确时间呢?

答案是:大多数情况下,进程是无法预测信号到达的精确时间的。什么? 难道还存在可以预测信号到达的情况? 有!这就跟信号的产生方式(signal generation)有关了。信号有两种产生方式:

(1)同步产生(synchronous)。

(2)异步产生(asynchronous)。

再强调一遍,这里的“同步”和“异步”描述的是信号的产生方式(signal generation),而不是信号本身。

系统进程处理信号是典型的异步事件,即进程无法预知信号到来的准确时间。但实际上,信号的产生方式却是可以分成两种,一种是以同步方式产生,与此相对的则是以异步方式产生信号。

异步方式产生信号是最常见的,可以通过一个进程发送信号给另一个进程,或者内核检测到某个事件而给进程发送信号,不管何种方式,他们都与当前进程的实际执行毫无关系。例如,用户按下CTRL+C字符,或者子进程结束时内核给父进程发送SIGCHLD信号。

然而,在另外一些情况下,信号的产生却是进程自己产生的,或者说信号的产生与进程自身的执行有关。例如:

(1)由硬件异常产生的信号(SIGBUS,SIGFPE,SIGILL,SIGSEVE,和SIGEMT)。它们都是进程自身执行了特定的非法指令导致的硬件异常。

(2)进程通过系统调用raise(),kill(),或者killpg()向自己发送信号。

在这些情况下产生的信号就是同步的,他们会立即递达给进程(除非进程之前阻塞了它们)。换句话说,同步发生的信号是可预知的、可重现的。

信号的生命周期

关于信号的生命周期,我绘制了一张图如下:

信号从产生到结束的过程

 

在解释上图之前,我们先了解下什么是信号集

顾名思义,信号集就是用来表示多个信号的数据结构,其系统数据类型为sigset_t。POSIX.1定义了几个函数来初始化信号集以及增删特定信号的操作函数,详细请man 3 sigsetops.

好了,知道了信号集的概念后,我们来解释下上图,上图过程可以用man 7 signal中的一段话来形容:

A signal may be blocked, which means that it will not be delivereduntil it is later unblocked. Between the time when it is generated and when it is delivered a signal is said to bepending.

Each thread in a process has an independentsignal mask, which indicates the set of signals that the thread is currently blocking. A thread can manipulate itssignalmaskusing pthread_sigmask(3).  In a traditional single-threaded application, sigprocmask(2) can be used to manipulate thesignal mask.

信号的产生:信号的产生(generation)原因很多,这里不再赘述。

信号的递达:实际执行信号的处理动作称为信号的递达delivery)。

信号的未决:信号从产生到递达之间的状态称为信号的未决状态pending)。

一个进程可以通过信号屏蔽字(signal mask)来有选择地阻塞(block)某个信号 -- 被阻塞的信号在产生后将保持在未决状态,直到进程解除对该信号的阻塞后才执行递达的动作。

由此我们可以得出以下结论:

  1. 一个进程必定拥有两个信号集,一个是上面提到的信号屏蔽字(signal mask),或者称为信号掩码,它是用来记录进程阻塞了哪些信号。另一个我们暂且称为未决信号集,未决信号集中的信号,要么是进程阻塞的信号,要么是还未来得及递达的信号。通俗点说的话,就是未决信号集里的信号是进程收到的所有信号,而信号屏蔽字未决信号集的子集。
  2. 当一个信号产生时,内核首先将其添加到未决信号集中,表明进程已经知道该信号的存在,但还没来得及处理,或者该信号被进程阻塞。
  3. 在进程执行过程中,内核会检测进程的未决信号集中是否有信号(每次从内核空间切换到用户空间时也会检测),如果有未决的信号且没有被进程阻塞的话,那么在运行信号的处理函数前,内核会在未决信号集中删除信号。如果有未决的信号但却是阻塞的,那么不做任何处理,继续处于未决状态,直到进程显示地解除阻塞。
  4. 进程的信号屏蔽字是可读写的(可通过函数sigprocmask获取和修改),而未决信号集是只读的(只能通过函数sigpending获取),进程是不能修改其值的,只能由内核来修改。

在《Linux C编程一站式学习》中有个图能很好的解释上述这些概念:

信号在内核中的表示示意图

在上图的例子中,

  1. SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
  2. SIGINT信号已产生,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作handler之后再解除阻塞。
  3. SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler

总结一下:

在信号的生命周期中,信号的未决是一种状态,指的是从信号的产生到递达信号这段时间内信号的状态,而信号的阻塞更像是一个开关,用来决定当信号处于未决状态时是否递达信号。注意,信号的阻塞容易让人产生误会,让人误认为是阻止信号的产生,这种认识是错误的。此外,阻塞和忽略也是不同的概念,忽略指的是当信号递达后可选的一种处理动作。

再来一张网友的图片,很不错。缺点是省略了信号的未决状态。


理解实时信号和非实时信号

信号分为可靠信号与不可靠信号,可靠信号又称为实时信号,非可靠信号又称为非实时信号。

之所以有实时信号和非实时信号的区分,是因为在它们产生(generation)之后,将它们添加到未决信号集中的方式有所区别导致的。

  1. 实时信号产生时,不管该信号在未决信号集中是否存在,都还是会再次加入未决信号集中,并对它们进行队列管理。因此,信号不会丢失,因此,实时信号又称“可靠信号”。
  2. 而非实时信号的处理就不一样了。非实时信号产生时,如果发现相同的信号已经存在于未决信号集中,那么系统会丢弃信号,对进程来说,相当于根本不知道信号的发生,信号丢失。如果未决信号集中不存在相同的信号,则会把信号添加到未决信号集中,此后如果再产生相同的信号,则会丢弃。 所以,非实时信号又称“不可靠信号”。

此外,我们需要知道的是,当信号正被递送时,即正在运行信号处理函数时,该信号是被阻塞的(默认情况下,是没有指定SA_NODEFER的)

参考链接:

http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index2.html 《Linux环境进程间通信(二): 信号(下)》

http://www.cis.temple.edu/~giorgio/cis307/readings/signals.html

http://www.programering.com/a/MjMyADMwATA.html 《Signal Linux system programming》

http://www.filibeto.org/unix/tru64/lib/rel/4.0D/APS33DTE/DOCU_006.HTM

http://m.blog.csdn.net/blog/hanqing280441589/43876983 《Linux信号实践(3) --信号内核表示》

http://www.cnblogs.com/lienhua34/p/4072417.html 《UNIX环境编程学习笔记(24)——信号处理进阶学习之信号集和进程信号屏蔽字》

http://blog.csdn.net/qq276592716/article/details/7325216 《Linux内核信号处理机制介绍》

http://blog.csdn.net/bullbat/article/details/7840405 《Linux信号机制概述》

http://m.blog.csdn.net/blog/wwangfeng2500/7649102# 《Linux内核信号处理机制介绍》

《Linux并发(异步信号)》

《信号“未决”与“阻塞”》

《Linux signal那些事儿》

0 0
原创粉丝点击