1.信号
①定义:信号是一种软件形式的异常。
一个信号就是一条小消息,他通知进程系统中发生了一个某种类型的事件。
②本质:每种信号类型都对应于某种系统事件。
③作用:硬件异常是由内核异常处理程序处理的,正常情况下对于用户是不可见的。
信号,作为一种软件异常,提供了一种机制,通知用户进程发生了这些异常,并可以编码对其进行处理。
2.信号的发送
原因:(1)内核检测到一个系统事件,比如被零除错误,或者子进程终止。
(2)一个进程调用了kill函数,显示地要求内核发送一个信号给目的进程。一个进城可以发送信号给自己。
注意:调用kill函数是说的kill系统调用,包含kill系统调用本身,以及间接调用kill的编程语言中的函数,以及间接调用kill的shell命令。
具体方法:
①/bin/kill ,使用完整路径是因为linux shell有内置的kill命令
②从键盘发送信号
比如ctrl-c表示SIGINT,ctrl-z表示SIGTSTP,注意这些信号会发送给当前shell的前台进程组的每一个进程。
③用kill函数发送信号
就是在程序中发送,kill(pid, 信号编号)或者会调用kill的函数比如unsigned int alarm(unsigend int secs)
3.单个信号的处理
(1)默认行为。
默认行为包括三种:
①终止
②停止知道遇到信号SIGCONT
③忽略
(2)捕获并处理
就是说信号对应事件发生时,采用一个用户定义的函数来处理。
捕获就是调用信号处理程序,处理就是执行信号处理程序。
这个程序就是signal()
声明如下
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
其中参数handler可能的取值是SIG_IGN,SIG_DFL,handler(这里是用户自定义函数的函数名)
分别表示忽略该信号,使用信号默认行为,调用用户自定义的函数handler()来进行处理。
注意:SIGSTOP和SIGKILL这两个函数的默认行为是不能被修改的,也就是说用户不能定义对于这两个信号的处理。
4.多个信号的处理
这里是说多个信号的情况。
待处理信号被阻塞
如果某一信号正在处理,其他信号到达,只要优先级没有当前处理信号的高,
那么来到的信号就会被放在等待队列中阻塞起来,等待当前信号处理程序处理完毕,再按优先级执行。
注意:同一种信号只能有一个处于等待。如果有多余的信号到达,此时新到的会被丢弃。
比如,正在运行信号A的处理程序,这个时候又有一个信号A到达,那么这个信号A被阻塞并等待,然后一个信号B到达,信号B被阻塞等待。
再然后又来一个信号A,这个信号A被丢弃。再来一个信号B也会被丢弃。
5.setjmp()+longjmp()VSgotoVS信号处理
简单地说,这几个都是跳转函数。
goto是局部跳转,也就是在一个函数内跳转。先要指定一个地方作为标识符。然后程序运行到goto处就能跳转到标识的地方。
longjmp()如其名字一样,可以实现任意位置跳转,究其原因是因为它会先用setjmp()保存环境,所以到时候跳转就能跳到很远的地方。
而goto没有保存环境,所以只能在当前环境,也就是本函数内跳转。
而信号处理,实现的跳转在handler执行完成之后必须返回到中断发生的地方。
而setjump()+longjmp()还有一个信号的版本,只是多了一个保存信号环境的选项。
这些都可以在linux上用man找到参数,返回值,用法信息。这里我简要说一下,更具体的信息可以用man。
函数声明:
#include <setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int retval);
由声明可知,
(1)setjmp的参数env,是一个结构体。是用来存放调用setjmp处的环境信息的。
值得注意的是setjmp会返回很多次。
最开始一次是保存环境时,成功调用保存环境信息,返回0.
其后再调用longjmp跳转到setjmp处时,setjmp函数可以返回retval的值,这个值可以是非0的任何int值。
这样函数后面就能通过判断这个返回值,进行相应地处理了。
(2)longjmp,有两个参数。没有返回值。
env参数,是将要跳转到的地方的环境值。
retval是要传递给setjmp,并让setjmp函数返回的值。