进程间通信机制详解(2)——信号

信号

信号是在软件层次上对中断机制的一种模拟,在原理上,可以认为进程收到一个信号与处理器收到一个中断请求是一样的。信号是一种异步通信方式,可以在任何时候发送给某一进程,而无须知道该进程的状态。

信号分类

可靠信号:也称为实时信号,信号值位于SIGRTMIN及SIGRTMAX之间,支持排队,即可重复在进程中注册,可以存在多个sigqueue结构,不会丢失。

不可靠信号:也称为非实时信号,信号值小于SIGRTMIN,不支持排队,即不可重复在进程中注册,最多只有一个sigqueue结构,当信号发生多次时,只会传送一次,导致信号丢失。

信号产生(发送)

信号事件有两个来源:

1)硬件来源,用户通过输入cltr+c(产生中断信号sigint),或者是终端驱动程序分配给信号控制字符的其他任何键来请求内核产生信号;当进程执行出错时,内核会给进程发送一个信号,例如非法段存取(内存访问违规)、浮点数溢出等。

2)软件来源,例如使用系统调用或者命令发出信号。一个进程可以通过系统调用kill给另一个进程发送信号,一个进程可以通过信号和另外一个进程进行通信。
发送信号的主要函数有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort()。
进程间通信机制详解(2)——信号

信号注册

内核处理进程收到的signal是在当前进程的上下文,故进程必须是Running状态。如果该进程并未处于执行状态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它。

在进程task_struct结构体中有一个未决信号的成员变量 struct sigpending pending。每个信号在进程中注册都会把信号值加入未决信号链表的末尾。只要信号在进程的未决信号集中,即表明进程已经知道信号存在,但还没来得及处理,或者该信号被进程阻塞。如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

非实时信号发送给进程时,如果该信息已经在进程中注册过,不会再次注册;
实时信号发送给进程时,不管该信号是否在进程中注册过,都会再次注册。

信号注销

在进程执行过程中,会检测是否有信号等待处理(每次从内核态返回到用户态时都做这样的检查)。如果存在未决信号等待处理且该信号没有被进程阻塞,则进程会把信号在未决信号链中占有的结构卸掉,注销信号。

对于非实时信号来说,未决信号集中最多只占用一个sigqueue结构,因此该结构被释放后,信号随之被删除(信号注销完毕);
对于实时信号来说,可能在未决信号集中占用多个sigqueue结构,只有当该信号的所有sigqueue处理完毕后,才把该信号从进程未决信号集中删除(信号注销完毕)。

信号响应(处理)

进程注销信号后,立即执行相应的信号处理函数。

进程先安装此信号,建立信号值和进程对相应信息值的动作。
信号安装函数:
(1)signal():不支持信号传递信息,主要用于非实时信号安装;
(2)sigaction():支持信号传递信息,可用于所有信号安装。

进程对信号的处理方式有3种:
1)执行默认操作,linux对每种信号都规定了默认操作。
2)捕捉信号,定义信号处理函数,当信号发生时,执行相应的处理函数。
3)忽略信号,当不希望接收到的信号对进程的执行产生影响,而让进程继续执行时,可以忽略该信号,即不对信号进程作任何处理。
有两个信号是应用进程无法捕捉和忽略的,即SIGKILL和SEGSTOP,这是为了使系统管理员能在任何时候中断或结束某一特定的进程。
默认信号操作
进程间通信机制详解(2)——信号

参考

进程间通信五(信号)
进程间通信:信号
深入理解Linux进程间通信(IPC)-- 信号signal
Linux 信号signal处理机制
Linux信号(signal)机制