Linux 中的信号

来源:互联网 发布:幻想神域数据库 编辑:程序博客网 时间:2024/06/08 17:59

1、基本概念 


软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。 

收 到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:第一种是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处 理。第二种方法是,忽略某个信号,对该信号不做任何处理,就象未发生过一样。第三种方法是,对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信 号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。 

在进程表的表项中有一个软中断信号域,该域中每一位对应一个信号,当有信号发送给进程时,对应位置位。由此可以看出,进程对不同的信号可以同时保留,但对于同一个信号,进程并不知道在处理之前来过多少个。




2.信号的产生


1. 用户输入命令,在shell下启动一个前台进程。

2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断。

3. 如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,CPU从用

户态 切换到内核态处理硬件中断。

4. 终端驱动程序将Ctrl-C解释成一个SIGINT信号,记在该进程的PCB中(也可以说发送了

一 个SIGINT信号给该进程)。

5. 当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,需先处理PCB中记

录的信号,发现有一个SIGINT信号待处理,用这个信号的默认处理动作是终止进程,所

以直接终止进程而不再返回它的用户空间代码执行



3.信号处理流程

 

 

对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个阶段:

1.信号诞生

2.信号在进程中注册

3.信号的执行和注销




阻塞信号

       实际执⾏信号的处理动作称为信号递达(Delivery),信号从产⽣到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block )某个信号。被阻塞的信号产⽣时将保持在未决状态,直到进程解除对此信号的阻塞,才 执⾏递达的动作。 注意,阻塞和忽略是不同的只要信号被阻塞就不会递达,⽽忽略是在递达之后 可选的⼀种处理动作。信号在内核中的表⽰可以看作是这样的:



block集(阻塞集、屏蔽集):一个进程所要屏蔽的信号,在对应要屏蔽的信号位置1
pending集(未决信号集):如果某个信号在进程的阻塞集中,则也在未决集中对应位置1,表示该信号不能被递达,不会被处理
handler(信号处理函数集):表示每个信号所对应的信号处理函数,当信号不在未决集中时,将被调用



结合处理信号的三种方式:

1. SIGHUP信号未阻塞也未产⽣过,当它递达时执⾏默认处理动作。

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

3. SIGQUIT信号未产⽣过,⼀旦产⽣SIGQUIT信号将被阻塞,它的处理动作是⽤户⾃定义函数sighandler。



常规信号在递达之前产⽣多次只计⼀次,⽽实时信号在递达之前产⽣多次可以依次放在⼀个队列⾥。因此,未决和阻塞标志可以⽤相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表⽰每个信号的“有效”或“⽆效”状态,在阻塞信号集中“有效”和“⽆效”的含义是该信号是否被阻塞,⽽在未决信号集中“有效”和“⽆效”的含义是该信号是否处于未决状态。




linux信号屏蔽字:



信号屏蔽字是指一个进程中当前阻塞而不能够递送给该进程的信号集。


信号集则是一个能表示多个信号的集合的一种数据类型,为sigset_t。


与信号集设置相关的函数有如下几个:


下列四个函数成功返回0,出错返回-1 int sigemptyset(sigset_t *set);int sigfillset(sigset_t *set);int sigaddset(sigset_t *set, int signo);int sigdelset(sigset_t *set, int signo);下面函数若真返回1,若假返回0,出错返回-1 int sigismember(const sigset_t *set, int signo);

sigprocmask()函数:

 功能描述:设定对信号屏蔽集内的信号的处理方式(阻塞或不阻塞)。用法:#include <signal.h>int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);参数:how:用于指定信号修改的方式,可能选择有三种:SIG_BLOCK //加入信号到进程屏蔽。SIG_UNBLOCK //从进程屏蔽里将信号删除。SIG_SETMASK //将set的值设定为新的进程屏蔽。set:为指向信号集的指针,在此专指新设的信号集,如果仅想读取现在的屏蔽值,可将其置为NULL。oldset:也是指向信号集的指针,在此存放原来的信号集。