我们在讲进程的多种状态时提到过,一个进程的退出有三种情况:正常退出,结果出错退出(代码也执行完了),异常终止退出(代码未执行完),其中最后一种退出相当于进程在运行时,突然收到某个”消息“,使自己不得不终止运行,这种”消息“就是信号。本文我们主要讲到什么是信号、产生的方式以及应用情景等。
一、什么是信号
在生活中,我们也会有很多信号,比如下课铃响了我们知道下课了,绿灯来了我们知道该走了,也就是说,它们在向我们发出某种消息,使得我们去做一些事情,在操作系统中也类似,信号就是其他进程,向目标进程发送异步事件的一种方式。所谓异步,就是指目标进程自己也不知道这个信号什么时候来,突然、随时的情况。
二、关于信号你需要知道的一些知识
1.我们如何识别信号呢?
识别信号是内置的。进程认识信号,是程序内置的特性。就相当于我们从小就被告知红灯停绿灯行
2.信号产生后该如何处理知道吗?如果没有产生,信号又该如何处理知道吗?
全都知道!因为信号处理的方法,在信号产生之前,就已经准备好了,就像我们从来没遇见红绿灯时,家长告诉我们如果遇到了应该这样做。
3.信号来的时候,我需要立即处理吗?
不一定,因为此时我正在做的事情优先级比较高,可能在某个合适的时候再进行处理。但进程需要把信号记录下来。
4.如何处理信号?
a.默认行为(我们早就被告知正常应如何做)
b.忽略信号(并不是不处理,而是遇见信号后对其完成忽略操作,比如闹钟响了我把它关闭并设置成一小时后再响)
c.自定义行为 (我虽然是被告知如果遇见信号该如何做,但是我也可以不听它的,按照自己的想法去做)
三、信号的产生方式
1. 键盘产生
我们知道,在Linux中想执行一个程序只需要输入 ./name即可,这种方式我们称前台进程。对应的还有后台进程(程序在后台运行)语法为 ./name &。二者的区别是:前台进程相当于把命令行解释占用了,当进程运行时,我们无法进行输入操作来完成某些命令,而后台进程运行时,我们依旧可以进行命令行解释(后台进程也可以把内容打印在显示器上)。我们之前提到的热键Ctrl+C,其实是终止前台进程的命令。至于如何终止后台命令,a.我们可以再打开一个终端然后找到进程的pid进行kill操作 b.我们在使用./name &时,它会显示一个下标和pid,我们只需要使用命令fg 下标(比如fg 1)即可把对应下标的进程放置前台运行,然后再ctrl+c。我们输入ctrl+c时,实质上是把某种信号给了前台进程,使其终止。至于信号的捕捉,我们有系统调用
其就是把指定的信号(参数1)按照自定义的方式(参数2)去捕捉
其中我们第二个参数要传函数的地址。函数的类型是void且参数是int(输出型参数,会用信号的序号赋值)
查看所有的信号我们用命令:kill -l
其中,我们的ctrl+c传给进程的就是2号信号(每一个信号名称都是宏)与此功能类似的是3号信号,默认也是终止,热键是ctrl+\ (我们只重点讲1-31号)
在1-31号中,大部分都是和进程终止相关的信号,且基本都能被signal捕捉,但有一个信号是绝对不可能被捕捉的——9号,它也是杀掉进程的信号,我们常与kill命令结合终止命令。
关于signal有两点补充:
(1)对于同一个信号,signal捕捉一次即可,不必放在循环中
(2) 若没有产生某种信号,signal中的handler一般不会被调用
言归正传,我们从键盘输入是如何转化成信号的?过程是,我们从键盘输入的内容,先是交给了OS,然后OS再把我们的内容转化为对应的信号传递给进程,但我们说过,进程并不是收到信号立马就处理,有时候也需要记录信号,那么进程记录信号的方式是:在PCB中创建一个位图(记录1-31号,比特位的位置为信号的编号,比特位是否为1表示是否收到对应的信号,所以,发送信号的本质是写入信号,即OS修改该进程PCB中的位图。
那么OS怎么知道键盘上有数据了?
我们引进一个名词——硬件中断,根据冯诺依曼体系,我们的键盘属于输入设备,按道理来讲OS会不断地检测键盘是否有内容输入,但现在不用了,当键盘输入完毕的时候,会向OS发出硬件中断的信号,OS收到信号再来获取数据。
2.指令中断
关于中断进程的指令,我们刚才也提到过,也就是kill
kill -num pid
3.系统调用
没错,kill也是系统调用,返回值小于0表示发送信号失败
除此之外,还有一个系统调用——raise
它的特点是,把你要传的信号序号进行传参,然后谁调用这个系统调用就把这个信号传给谁。
还有不传参版的——abort
4.软件条件
在OS中因某些软件还没准备好,或不具备某种条件而产生的信号方式就是软件条件。比如我们之前提到的管道,当管道的读端关闭写端仍要写入,操作系统就会发送信号(13号)杀死这个进程,这就是软件条件不具备。除此之外还有一个例子——闹钟
可以设定我们的进程在多长时间后自动终止。即到指定时间后由OS向进程发送指定信号(14)
至于其返回值,当alarm传参为0时,表示取消闹钟,此时返回值就是上一个闹钟的剩余时间。
5.异常
进程出现异常的情形大多数是因为野指针、除0操作,当进程出现异常了,OS会向进程发送8//11信号来杀死进程。
四、core与term
我们查信号手册时,发现有的进程是core有的是term,他们有什么区别呢?
term类型是正常终止进程,而core类型比它多做了一件事——核心转储
当进程收到信号要终止时,会在当前目录下形成文件->pid.core,当进程崩溃时,会把进程在内存的信息保存起来,方便后续调试。但云服务器一般是关闭core的这个功能的。