第十章 信号
一:主要内容:
信号属于软件中断,它提供了一种异步处理事件的方式。本章对信号机制进行综述,说明每一种信号的用法,然后分析早期实现的问题,之后说明解决问题的方法。
二:信号概念
每个信号都有名字,他们都是以SIG开头,信号在signal.h文件中被定义为正整数常量,并且不存在编号为0的常量。
产生信号的方式多种多样,比如最常见的就是在终端中ctrl+c,就可以产生中断信号。或者当程序除于0也会产生信号。进程调用kill(2)函数可已经任意信号发送给一个进程或者一个进程组,当然我们很容易推向出发送信号的进程一定要和被发送的进程或者信号组的所有者一致,或者发送进程的所有者为超级管理员。
信号是异步事件的经典实例,产生信号的事件对进程而言是随机出现的,进程不能简单地测试一个变量来判断是否发生了一个信号,而是必须告诉内核:如果发生了 一种信号,我们该做什么操作。
在某个信号出现时,我们可以告诉内核按下列三种方式之一来进行处理,我们称之为信号的处理或与信号相关的动作。
1.忽略此信号,大多数信号都可以被忽略,但是信号SIGKILL和SIGSTOP不能被忽略,因为他们向内核提供了
2.捕捉信号,为了做到这一点,需要通知内核在某种信号发生时,调用一个用户函数。
3.执行系统默认动作,下图为系统的默认动作。
三:信号signal
UNIX系统实现的最简单的接口是signal函数,声明如下:
signo参数是信号名,func的值是函数指针,也可以是SIG_IGN或者SIG_DFL。如果是SIG_IGN代表忽略这个信号,如果是SIG_DFL,则代表执行系统默认动作。
上述函数原型过于复杂,通常我们会通过一些其他的技巧来使得使用这个函数更简单。
当我们执行一个程序的时候,所有的信号的状态都是系统默认或者忽略。通常所有的信号都被设置为他们的默认动作,除非调用exec的进程忽略该信号。确切的讲,exec函数将原先设置为要捕捉的信号更改为默认动作。
一个具体的例子是一个交互shell如何处理对后台进程的中断和退出信号。对于一个非作业控制shell,当在后台执行一个进程时,例如:cc main.c &
shell自动将后台进程对中断和退出信号的处理方式设置为忽略。
四:不可靠的信号
早期的信号是不可靠的,这里的不可靠指的是信号可能会丢失,这会导致一个信号发生了,但是进程却一直不知道。而且当时对信号的控制能力也很差。早期版本中的一个问题是进程在接收到一个信号并对其处理,但是会将该信号动作重置为默认值。这个问题可能会体现在,当第一个进程在处理信号的时候,会有一段处理时期,但是这时该进程将信号设置为了默认值,当第二个信号被处理的时候会执行默认动作,这会导致与预期的程序设定不一致。