Bootstrap

Linux初识进程信号

预备

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就可以定位到错误的地方:

;