【Linux】初识信号
目录
一、人眼中的信号 VS 进程眼中的信号
二、Ctrl+C终止一个前台进程
三、signal函数--验证2号信号
四、查看信号信息
五、sigaction函数的三种处理动作方法
六、信号的处理方式
七、ctrl+c 被解释成2号信号验证
八、ctrl+c 是如何变成信号的?
九、初步理解信号
十、完结

一、人眼中的信号 VS 进程眼中的信号
人眼中的信号是什么样的?
我们举个例子:当我们在马路上等红绿灯的时候,比如说正在等绿灯。
在绿灯到来前(此时还没有绿灯),我们就先知道绿灯到来我们该干什么,这个叫做知道信号的处理方法。但是在知道信号的处理方法前,我们一定要先认识绿灯,这个叫做识别信号
我们把这两个事物规定为:认识信号
所以认识信号包括:识别信号和知道信号的处理方法。
我们刚才说到过,即使信号没有产生,但我们依旧知道我们该怎么做,这一点很重要。
信号产生了,我们可能并不立即处理这个信号,而是在合适的时机去处理,因为我们当前可能正在做更重要的事情,所以在信号产生后一直到信号处理前,有一个时间窗口,在这个时间窗口内,我们必须记住信号的到来。
进程眼中的信号:
进程眼中的信号就像人眼中的信号一样
- 进程必须能够识别、处理信号,即使信号没有产生,也要具备处理信号的能力。信号的处理能力,属于进程内置功能的一部分。
- 进程即便是没有收到信号,也能知道哪些信号该怎么处理。
- 当进程真的收到了一个具体的信号的时候,进程可能并不会立即处理这个信号,在合适的时候处理。
- 一个进程必须当信号产生了,到信号开始被处理,就一定会有时间窗口,进程具有临时保存哪些信号已经发生了的能力。
现在我们来实体化感受一下信号的存在

用户输入命令,在Shell下启动一个前台进程
用户摁下Ctrl+C,因此键盘的输入产生了一个硬件中断,被操作系统(OS)获取,但是OS并不能直接理解Ctrl+C是什么东西,所以操作系统把Ctrl+C解释成为信号,发送给目标前台进程
前台进程因为收到信号,进而引起进程退出
未知名词解释:
前台进程:前台进程是指直接连接到当前终端会话、会占据终端输入输出,且在其运行期间,你在该终端里没法执行其他命令(除非它结束或被放到后台 )的进程
我们在终端里能直接看到它的运行状态(输出、等待输入等),且操作终端会直接影响它
粗略理解就是我们可以在显示器上直接看到。
二、Ctrl+C终止一个前台进程
我们刚才的图片中,使用的是Ctrl+C使这个程序停止运行的。
它的本质其实是Ctrl+C终止掉1个前台进程。Linux中,一次登陆中,一个终端会配上一个 bash ,bash也是进程,每一个登陆只允许1个进程是前台进程,可以允许多个进程是后台进程。
在我们打开操作系统什么都没干时,bash就是一个前台进程。也就是说当你打开终端但没有运行任何其他程序时,bash 就是前台进程。
例如我们在操作系统重输入指令:pwd,这时候bash就是前台进程,因为我们并没有运行其他任何程序
但是我们在刚才的图片中,我们执行了自己的程序,这个程序是由bash创建的独立的一个新进程去运行的,所以此时bash就成为了后台进程(因为一个登陆的前台进程只能存在一个)
那么图中的bash就成为了后台进程,此时再向 bash 中输入指令是没有任何反应的
(一定是没反应,不是因为bash是后台进程我们看不到。因为我们的指令是在终端输入的,因此只有前台进程能接收键盘输入,后台的bash进程根本收不到)
如图:

可以看见确实没有反应
前台进程和后台进程的一个本质区别是,谁来获取键盘输入,只有前台进程才能拿到键盘输入。
如果我们想让一个程序成为后台程序去运行,我们就需要这样写
./可执行程序 &
后台进程运行如图:

可以看到此时我们的Ctrl+C已经终止不了后台程序了。这里后台程序依旧可以被我们看到,是因为我们上面提到过,后台程序与前台程序的不同是谁来获取键盘输入,而不是谁能被用户看到。
终止后台进程指令:
pkill 可执行程序名
//我们的例子中可执行程序名为red
//所以我使用的时pkill red
重点:
ctrl+c 本质是被操作系统解释为 2 号信号。再将2号新号发送给进程,**进程收到2号信号的默认动作就是终止自己。
三、signal函数--验证2号信号
我们在目录二的结尾提到了,Ctrl+C终止前台进程的本质是被操作系统识别为2号信号。
那么接下来我们来验证一下它到底是不是2号新号
这里要用到一个系统函数:
#include<signal.h>
sighandler_t signal(int signum,sighandler_t handler);
参数说明:
signum : 信号编号[后面会解释,现在只需要知道是个数字]
//第一个参数填写SIGINT代表由键盘输入产生的中断信号(后面会讲先短暂记住一下)
//第一个参数输入数字2代表自定义捕获信号编号为2的信号,以此类推handler : 函数指针。表示更改信号的处理动作,当收到对应的信号,就回调handler方法
接下来我们实战用一下:

可以看到,确实Ctrl+C的信号量是2
声明: 也可以写成 signal(2,handler);
四、查看信号信息
信号是进程之间事情异步通知的一种方式,属于软中断。
名词解释:
异步:信号的发送和接收是相互独立、不同步进行的。
也就是说我发送信号不管你能不能接受,只要我满足信号发送的条件,就直接发送信号
接受也是同理
软中断:软件层面产生的硬件中断,用于通知进程处理特定事件
举个例子:你在家里看书,突然门铃响了,你就不得不放下书去看一下是谁来了
软件层面产生硬件中断解释:
例子 1:程序出错时,操作系统自动发信号(软中断)
你的代码中出现 a/0 ,不可以除0,所以程序出错了,发送信号。
例子 2:用命令手动给进程发信号(软中断)
假设你在终端运行
./myprocess,然后打开另一个终端输入:kill -10 12345 # 12345是myprocess的进程ID
这个命令会给
myprocess发送信号,此时如果myprocess在处理其他事情,就会暂停当前工作去执行处理逻辑。
这里我们介绍几个常用的指令:
pidof myprocess:显示操作系统中所有 myprocess 进程的 pid。
pidof myprocess | xargs kill -9:杀掉当前操作系统启动的所有 myprocess 进程。
kill -l:查看系统的信号列表。

信号没有0、32、33号信号,一共有62个信号。1-31号称为普通信号;34-64号称为实时信号,进程一旦收到实时信号,必须立即处理。
信号本质上就是数字,右边的字符是信号的名称,在操作系统的内核中,信号一定是以宏定义的方式提供的,这些宏定义在 signal.h 中可以找到。
在宏定义找到:
#define SIGINT 2以此类推
再介绍一个新的指令:
man 7 signal:查看信号的详细说明。

其中 Term、Core 表示终止;Ign 标记忽略;Cont 表示继续;Stop 表示暂停。
五、sigaction函数的三种处理动作方法
1. SIG_IGN 忽略此信号

signal的第二个参数: SIG_IGN 可以忽略信号,可见我们输入Ctrl+C后并没有终止进程,而是忽略了
2.SIG_DFL 执行该信号的默认处理动作

3.自定义信号处理函数
我们最开始展示的就是自定义了信号处理函数(函数handler),这种方式叫做自定义捕捉一个信号
六、信号的处理方式
进程收到信号有三种处理方式,这三种处理方式就是我们刚才所演示的三种
- 默认动作:人看到红灯,默认动作就是站在原地,等待红灯结束。
- 忽略:人看到红灯之后,不管红灯,继续往前走。
- 自定义动作(信号的捕捉):人看到红灯后,开始唱歌。
进程收到一个信号后,它的处理动作只能在上面这三个动作中进行三选一。
七、ctrl+c 被解释成2号信号验证
5.1 signal——设置自定义捕捉方法
signal——设置进程对某个信号的自定义捕捉方法:当进程收到 signum 信号的时候,去执行 handler 方法。

signum:信号的编号。
handler:一个函数指针,指向信号的自定义捕捉动作。
sighandler_t:一个函数指针类型,指向一个返回值为 void 参数为 int 的函数,这个参数值就是收到的信号。为什么要有这个参数呢?因为同一个自定捕捉方法,可以捕捉多个不同的信号,所以在该方法中需要知道是收到哪个信号才来执行的该方法。
signal 函数只需要设置一次,往后都有效。sighandler_t 函数只会在收到对应的信号后才会执行,假如程序一直没有收到对应的信号,那么该函数就一直不会被调用。
这里不演示了,因为我们之前一直在用的就是signal这一个函数
八、ctrl+c 是如何变成信号的?
由于进程无法访问硬件资源,所以当我们摁下键盘后,一定是操作系统先知道的。
但是操作系统怎么知道我们摁的是什么的?
在数据层面,CPU 是不会直接和外设打交道的。
但是在控制层面,当外设有数据了,外设可以给 CPU 发送硬件中断。 中断都有自己的中断号,硬件中断就是这样,CPU 通过它的中断号来判断该中断是哪个外设发送的。之后 CPU 会以这个中断号为下标,去操作系统的中断向量表中执行对应的方法(也就是执行所对应的程序),接着这个程序会将中断向量表所对应的硬件数据读取到内存中。
当操作系统识别到这些特殊数据后,不会将数据拷贝给目标进程。而是转化为向目标进程发送信号,从而将目标进程退出或暂停等行为!
(名词解释: 硬件中断:硬件中断不是信号,是信号产生的源头之一)
操作系统在将硬件数据拷贝到内存之前,会先判断输入的是数据还是控制,如果是控制,ctrl+c 就是控制,会被操作系统转换成2号信号并直接发送给进程,让进程按默认规则(通常是终止)响应。

小Tips:键盘和显示器有各自独立的文件页缓冲区:
九、初步理解信号
信号其实是从纯软件角度,模拟硬件中断的行为,只不过硬件中断是发给CPU的,而信号是发给进程的,两者有相似性,但是层次不同
十、完结

