预备
1,你怎么能认识信号呢?
信号是内置的,进程认识信号,是程序员内置的属性
2,信号产生之后,怎么处理信号?
知道!因为在信号产生之前,就已经把处理信号的内容准备好了。
3,处理信号,是立即处理吗?
我可能正在做我自己的事情,优先级很高,有时候信号并不一定立即处理,而是在合适的时候。
4,怎么处理信号?
a,默认行为
b,忽略信号
c,自定义动作
信号产生
1,键盘产生
我们用一个死循环的代码来讲解:
这时终端会不断的向屏幕打印内容,直接./运行的程序属于前台进程,当想在此进程运行时输入诸如ls之类的指令时无法运行:
我们还知道,当我们输入CTRL+c时会退出程序运行,这时候才能输入命令:
我们输入CTRL + c的动作就是给前台进程发信号让进程停止运行。
这时我们让进程进入后台运行:在./ 后面加上取地址符号:
这时前台进程空出,bash进程可与进行命令行解释:
那么怎么关后台进程?
1,用ps jax | grep + 进程名查进程pid:
用指令:kill -9 +进程id:
2,nohup方法:
用指令:nohup + ./test + &
可以看到,文件夹中多列一个nohup文件,cat此文件时会看到文件内有进程打印到屏幕中的内容.
这时我们看到nohup时下面有个数字1,然后用fg指令加这个1可以把进程拉到前台然后CTRL+C:
可以看到,进程被关闭:
3,常见信号:
可以看到系统提供了这么多种信号,其中1号到31号常用,34-64为时实信号,不做讲解.
其中,2号信号就是我们从键盘中输入ctrl +c时给进程发送的信号:
为了测试这个结论,我们要学习一个系统调用接口:signal
此函数可以让我们实现信号捕捉/自定义,signum代表信号,handler代表当此信号触发时运行此函数:
我们可以去man 7手册中查看各自信号代表什么含义:
其中,ctrl +\ == 三号信号,也是可以停止进程:
这时我们可以用ctrl + \来停止:
那如果,我们将所有信号都包装了那岂不是进程就无法关闭了?
起始在1到31个信号中,有一个信号最为特殊,就是九号信号,此信号无法被封装:
我们如何在软件层面理解信号处理:
键盘把组合键给到os,再有os传给进程,那么如何记录信号?
位图!
比特位为信号的编号,比特位的内容为0/1表示是否受到信号
所以发送信号的本质就是写入信号,os'修改目标进程的pcb中信号位图由0变1;
无论以什么方式发信号,最终都转换到os,让os写入信号,所以进程的唯一管理者是os
我们如何在硬件出卖你理解信号:
os怎么知道键盘上面由数据?
在硬件设备中纯在着一个中央处理器,平时os都不会对键盘的信息做读取,但是当键盘由内容输入且传输的时候,中央处理器会接收到来自键盘的信号,知道有外设的数据已经准备好了,然后再告诉操作系统从外设中读取数据,这个过程我们叫做中断,
信号为纯软件,模拟信号中断.
有了以上知识的铺垫,我们可以来学习一些代码中的系统调用接口:
kill:
其中,pid指的是需要传入信号的进程pid,sig指的是传几号信号.
raise:给自己传信号:
abort:给自己调用六号信号(kill(getpid(),6);
alarm:可以设置多少秒的闹钟,默认闹钟结束行为为中止进程,给进程发送SIGALRM信号.
alarm(0)为取消闹钟,然后返回闹钟剩余时间.
2,软件条件
在之前的文章中我们知道,alarm可在进程中设置闹钟让进程在一定时间后收到某信号执行信号内容,这种方式就是属于软件条件产生信号.
所以我们现在知道的五种信号产生方式:
1,键盘
2,指令,
3,系统调用,
4,软件条件
5,异常(下面重点讲)
异常
当系统发现段错误的时候,会给os发送11号信号让进程停止运行
c/c++中常见的异常机就是进程崩了,然后告诉os然后os发信号给进程
那么os怎么知道进程内出错了?为什么当我们把11号信号自定义之后会出现死循环的情况:
其实我们的程序错误,都会体现在硬件上:
在cpu中有一个Eflags硬件,其中有一个标志位代表着是否会越界的问题,当此标记为为1时,cpu会返回给os告诉os这个进程出错了,然后os会给进程发送11号信号,但是在上面代码中,我们把11号信号自定义了,所以程序还会继续跑,继续跑继续发现错误然后继续防窥如此循环:
当发生除零错误时,cpu中还有一个硬件叫MMU,当除法位数超过MMU标记为时也会返回给操作系统然后同上(除零错误返回八号信号)
其他问题:
在man 7 手册中会看到有一栏:
term和core代表什么意思?
Trem代表正常退出,不做其他处理.
core会在当前目录形成一个文件:pid.core,在进程奔溃的时候将进程中部分信息保存下来方便调试,云服务器一般都是默认关闭这个功能,因为一旦出错可能会无限创建core文件导致磁盘塞满会引发其他问题.
可以用ulimit查看:
可以看到,core部分为0 这时候可以用指令打开:
关闭值为零就行;
这时运行就会产生core文件.
编译时带-g,
gdb+进程名
输入core-file core就可以定位到错误的地方: