目录
前言
哈喽,小伙伴们大家好,本篇文章我将和大家一起学习进程信号。进程在某种意义上其实和我们人很像。在大多数情况下,我们的日常生活就是起床、上课、学习、休闲、休息,按部就班的度过每一天。但有时候也会遇到突发状况,比如生病啦,或者家里突然有事需要回家啦,这些突发状况是不可避免的,因为往往是事情推着人走的,我们要有处理突发状况的能力。进程也是如此,通常情况下按部就班的运行着,但保不齐什么时候就遇到突发状况,为了保证进程能在突发状况中做出相应的处理,信号由此产生。操作系统会根据突发状况给进程传递不同的信号,让进程做出相应的处理。看到这里,大家是不是感觉到了信号是一个非常有用的东西呢,那么事不宜迟,拿好小本本,和我一起开始信号的学习吧。
一、信号概念
1、生活中的信号
信号不仅仅存在计算机中,同样存在我们的日常生活中。在谈计算机中的信号前,我们先来聊聊生活中的信号。
在日常生活中,信号与我们的关系有如下特征:
- 信号还没有产生的时候,我们要知道如何识别信号,并且知道接收信号后该如何反应。比如我们过马路时,我们首先需要知道红绿灯是一种信号,并且知道根据颜色的不同做出什么反应。这些东西往往是小时候爸爸妈妈教给我们的。所以我们得出一个结论:我们能够识别的信号特征,以及相应的处理过程是因为之前有人对我们进行过"教育"。
- 当信号产生的时候,我们不一定要立刻去处理信号,因为我们可能有优先级更高的事情。比如我们正在打游戏的时候显示快递到了,我们不会立刻去取,而是等游戏打完后找一个合适的时间去取。
- 信号已经产生,但我们暂时没有处理,那么一定要有某种方式记录这个信号已经产生。比如我们收到快递到了的信号后没有立刻去拿,但手机里的短信记录着快递已经到了。
- 处理信号时往往有三种方式:默认行为,自定义行为,忽略行为。比如我们在过马路的时候遇到红灯,默认行为是站在原地等。但有一次我突然想上厕所,于是趁着红灯的时间去了一下路边的厕所,这就是自定义行为。而忽略行为就是不管红灯的提示,径直走过马路。
2、计算机中的信号
在计算机中,进程就好比生活中的人,信号有以下特征:
- 进程虽然现在没有受到信号,但是进程一定知道如何识别信号和做出相应反应。程序员在设计进程的时候已经内置了处理方案,信号是进程中特有的特征。
- 进程在收到信号时可能不会立即处理,因为有优先级更高的事情。如果这样需要先把信号记录下来,等合适的时候再处理。
- 进程处理信号有三种方式:(1)默认行为:终止进程,暂停,继续运行等。(2)自定义行为,由我们自己编写。这种方式也称为捕捉一个信号(3)忽略信号。
可以看到,计算机中的信号和生活中的信号其实是很相似的。下面我们思考两个问题:
信号是如何记录的?
我们先来谈谈信号是如何记录的,在学习进程时候,我们应该了解了每个进程都对应一个task_struct(PCB),在这个task_struct中,记录着进程的各种信息,各种信息中同样也包括信号的记录。信号在task_struct中是以位图的方式记录的,task_struct有变量signal,可以把它的类型理解成无符号整数。比特位的位置为信号编号,比特位的内容为是否收到信号,假如收到6号信号就会把第六个比特位置1。我们可以通过下面的命令查看信号编号。
命令:kill -l 功能:查看系统定义的信号列表
- 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定义 #define SIGINT 2
- 31号之前为普通信号,34号之后为实时信号,本章我们主要讨论普通信号。
信号是如何发送的?
进程收到信号,本质上是进程的信号位图被改了。那么谁有权限改进程内的东西呢?答案当然是OS,操作系统是进程的管理者,拥有绝对的权限。所以信号发送的本质就是操作系统修改了进程的信号位图,进程根据修改后位图的值做出相应处理。
3、实现信号捕捉
signal函数
原型:signal(int sig, void (*func)(int))
功能:用来自定义信号处理方式
参数:
- sig:信号编号
- func为函数指针,传入的函数为信号的处理方式
代码如下:
代码运行结果如下,ctrl+c对应的是信号2,终止进程。我们可以发现信号2被我们自定义了。
注意:有些信号是不能被捕捉的,因为如果所有的信号都被捕捉,那么操作系统就再也没有办法杀死进程了。
二、产生信号的方式
1. 通过终端按键产生信号
通过终端按键也就是通过键盘产生信号,比如我们常用的ctrl+c。ctrl+/。
注意:
- Ctrl-C 产生的信号只能发给前台进程。Shell可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl-C 这种控制键产生的信号。
- 一个命令后面加个&可以放到后台运行,bash默认是前台进程,这样bash(Shell)不必等待进程结束就可以接受新的命令,启动新的进程。
- 前台进程在运行的任何时候都可能收到ctrl+c产生的信号发生终止,所以说信号对于进程的控制流程来说是异步。
格外拓展:核心转储(core dump)
man 7 signal 功能:查看信号详细信息
从上面我们可以看出:SIGINT的默认处理动作是终止进程,SIGQUIT的默认处理动作是终止进程并且Core Dump,接下来我们来验证一下。
再验证之前我们先来学习一个概念:Core Dump
在程序正常结束后,