本篇博客我们开始讲述Linux中新的模块:进程信号。
在这一模块中,我们需要讲述的内容有:进程信号的概念,信号的生命周期,函数冲入和关键字。
目录
1.信号概念
2.生命周期
2.1产生
2.1.1kill接口:
2.1.2raise接口
2.1.3abort接口
2.1.4alarm
2.2注册
2.3注销
2.4处理
3.信号阻塞
3.1sigprocmask接口
在Linux中我们需要了解的信号概念:软件中断 -- 通知一个进程发生了某个事件,打断当前进程的操作,去完成新发生的事件。(信号一定是多种多样,且能被识别的)
在之前的进程概念中我们提到过进程具有一种“可中断休眠态,”打断该状,态的休眠,便是由信号来完成的。进程休眠被打断后,意味着某些事件等待执行,这也是我们打断进程休眠的目的。
输入kill -l 指令,我们便可查看Linux中所有信号的内容,我们可以发现31~34中间不存在32和33信号,所以信号共计有62种信号。
对于前31位信号都是有独特的名称的,对于后31位信号没有独特的名称且和数字的加减组合在一起。 这意味着对于前31位信号肯定各自都代表着一种事件,而对于后31位信号不一定一一对应某种事件。
造成这样的原因是来自于Linux发展过程中积累造成的,对于前31位信号中,我们可以发现其中10和12位信号名称:"SIGUSR1"和“SIFUSR2”,这便是设计者为使用者设计出可供自己定义的信号。但是随着发展,这两种信号不足以完成一些较大的内容,所以后来的设计者便在原有31位信号的基础上,添加定义了后31位信号。
前后31位信号的特性:
其中可靠性好和非可靠信号的区别就在于:信号所代表的内容能否一定被执行;实时信号和非实时信号的区别在于:二者共同发送给进程,实时信号处理的优先级要高于非实时信号。
对于每种型号的具体内容介绍,笔者引用apue(圣经)中的介绍:
信号的生命周期有四个阶段:产生 -> 注册 -> 注销 -> 处理。
信号的产生:有两种产生方式,硬件产生和软件产生。
虽然二者的操作方式不同,但是二者的本质都是向操作系统发送一个信号,来对进程实现干预。
int kill(pid_t pid, int signum);
kill接口的作用便是向指定的进程发送一个指定的信号。
通过对kill接口进行简单的编写,便可得到一些结果的显示:
int raise(int signum);
raise接口的作用便是向进程自身发送一个信号。
void abort();
abort接口的作用便是向进程自身发送一个SIGABRT信号(异常退出信号)。
int alarm(int sec);
alarm接口的作用便是sec秒之后向进程发送一个SIGALRM信号(超时)。
信号的注册:在进程中做标记,让进程能够知道自己收到了某个信号。
原理:在进程pcb中存在一个pending未决信号集合--位图(标记进程收到了某个信号),当我们向进程发送一个信号,便是给sigqueue链表中添加一个对应信息的节点,并且修改位图,将对应的信号值制1。
但是信号存在可靠信号和非可靠信号的区别,所以对于具体原理上,我们仍需要在原有基础上加以分类处理。
对于非可靠信号,当注册新信号时,若没有被注册,则注册并创建;若已经注册,则丢弃;
对于可靠信号,当注册新信号时,无论之前有无被注册,都会添加新的信号信息节点。
在信号被处理之前,我们便需要将信号注销,销毁信号存在的痕迹,这是为了防止该信号被重复处理。信号的注册同位图和信号链表有关,那么对于注销其实是与之相反的操作。
对于非可靠信号的注销:删除信号的信息节点,位图制0;
对于可靠信号的注销:删除信号的一个信息节点,当没有相同节点则位图制0。
在语言学习过程中,我们善于将每项功能封装成函数,对于信号的处理也是如此。信号的处理便是调用信号的事件处理函数。
信号的处理存在三种方式,分别为:
自定义处理的相关接口:
自定义的数据类型 :
typedef void (*sighandler_t) (int);
signal接口:
sighandler_t signal(int signum, sighandler_t handler);
signal接口会使用handler函数,替换掉signum信号当前的处理函数。即当进程收到signum信号,会使用handler函数进行处理。
其中handler存在两个关键字:SIG_DFL:信号默认处理方式和SIG_IGN:忽略处理。
我们编写一个简单的程序,来对signal接口进行使用:
然后便可发现它的执行结果如下:
我们使用ctrl + c 的方式发送SIGINT信号无法将程序打断,因为我们在程序中将其替换成忽略处理。这便是signal接口的作用:替换信号执行函数。
信号阻塞的概念:信号依然会被注册,但是信号暂时不会被处理。(直到被解除阻塞)
信号阻塞的原理:在进程pcb中存在一个block阻塞信号集合,当有信号被添加到block阻塞集合之中,就表示该进程暂时不处理该信号。
int sigprocmask(int how, sigset_t *set, sigset_t *old);
sigpromask接口用于操作阻塞,其中how:要对pdb中的信号阻塞集合进行的操作;old:将修改前的block集合中的信息添加到old(便于还原)。
set相关关键字:
返回值:成功返回0;失败返回-1。