【 Linux 】信号的产生

什么是信号?

在生活中就有许多常见的信号,如红绿灯就是最常见的信号。

红绿灯信号没有产生,我们就已经知道如何处理这个信号,

红绿灯信号的产生相对于我们的工作是异步的,

红绿灯信号的产生,我们不一定会去立马执行,总是挑选最优时刻执行,因此能够被保存

信号就是向目标进程发送通知消息的一种机制。

它的产生是异步的,并且我们知道如何处理,会选择在合适的时候处理。


因为信号需要知道如何处理,所以必然会有标志认识信号,并有对应的方式处理。

查看信号

kill -l

【 Linux 】信号的产生_第1张图片

信号的形式是宏定义,既可以通过编号,也可以通过名称标识。

信号不是从0号位置而是从1号开始

是因为 0被设为进程正常退出时的状态码

从 1到 31是普通信号,本文主要介绍的就是普通信号。

信号本质就是用软件 来模拟中断行为 

比如说OS发送了信号2 ,那么就会在 中断向量表中,找到函数指针,调用对应的方方法处理信号

【 Linux 】信号的产生_第2张图片

这里有个简单的认识,后面会具体介绍。

信号的合适处理

就有三种情况:
1.立即处理

2.忽略

3.用户自定义处理

必要知识:

Linux中,程序运行时,前台只能有一个进程,后台可以有许多进程。

bash也是进程,所以在进程启动时,默认会将bash切换到后台,那么在键盘输入,bash也不会识别。

比如说  进程 ./myfile 是启动前台进程 

 ./myfile &是启动后台进程。

没有能力接收用户输入的是后台进程。

CTRL +c 是终止前台进程       CTRL + Z是暂停 

因为前台进程不能被暂停,所以要立即被放到后台上

认识signal函数

用于对信号重定向方法

本质就是将中断信号表上的函数指针替换

【 Linux 】信号的产生_第3张图片

参数说明:
signum :信号标志

handler : 是一个函数指针 该函数指针的返回值是void  参数是int


举例使用:
 组合按键CTRL+ c 是向发送 2 号信号,目的是终止前台进程

就对2号信号 重新写入方法

【 Linux 】信号的产生_第4张图片

每隔一秒打印 I   am running  pid

CTRL +c 无法终止掉进程

【 Linux 】信号的产生_第5张图片


OS如何知道键盘有数据输入?

这就涉及到中断,OS不可能一直轮询等待键盘的输入

【 Linux 】信号的产生_第6张图片

CPU是有许多的引脚,每一个引脚通过中断控制器连接外设。

中断控制器上有编号,代表一个外设。

当键盘输入时,比如说2号引脚亮了,就会识别到是键盘输入,然后将数据传入OS

OS会识别是否为那32的特殊的信号,是的话将位图上的对应编号的0变为1 ,然后回调函数。


信号的产生

有了上面知识的铺垫,就来看一看信号产生的方式

首先就是最常见的键盘输出信号

  1. 键盘输入产生

ctrl+ z是暂停程序 ctrl+\是终止程序。

CPU通过中断的方式读取到键盘输入,交由OS识别是否为特点的信号,如CTRL+C 被识别为2号信号,然后交由函数指针的数组,回调对应的方法,终止进程。

对于普通信号来说,进程接收到某个信号,需要标识自己接收到。

标志的方式是位图

32个比特位 1--31标识信号

如果 6号进程被识别到

那么位图上第7位 就要从0-》1

【 Linux 】信号的产生_第7张图片

所以

  • 进程PCB必定要维护一张函数指针数组,用来处理信号
  • 必定要维护一张位图,用来记录信号

通过系统调用 指令

查看kill指令

man 2 kill
       #include 
       #include 

       int kill(pid_t pid, int sig);

kill函数是系统调用

参数:
pid 是需要发送信号的进程

sig 是信号编号

返回值

成功返回0

失败返回-1

举例使用kill:

下面设计一个简单的系统调用

main函数的可变参数

第二个参数是指针数组,里面放着是字符串的地址

第一个参数argc是字符串的个数

进程运行跟上pid 和信号 

创建myfile.cc

【 Linux 】信号的产生_第8张图片

创建一个简单的死循环,利用系统调用终止进程

【 Linux 】信号的产生_第9张图片

进程被终止,就像我们常用的指令 kill -9 5690


raise向该进程发送

       #include 

       int raise(int sig);

谁调用raise,就向谁发送信号

【 Linux 】信号的产生_第10张图片

用户自定信号2函数的方法

五秒后,会调用信号2

输出get a signo:2 


abort( )

       #include 

       void abort(void);


 

向该进程发送信号6

一般来说,SIGABRT信号(信号6)通常表示程序中存在某种严重错误,如内存损坏、无效的参数或逻辑错误等,导致程序无法继续执行。 当程序接收到SIGABRT信号时,它会立即终止,并且不会执行任何清理操作(如关闭文件、释放内存等)。


异常产生信号

是由硬件引起的。当我们的进程出现除0,和野指针,越界等等,程序会崩溃。本质上就是进程接收到OS发来的信号终止程序。那么OS是如何识别到,并触发信号。

除0异常

CPU是有寄存器,通常一个寄存器会维护一个变量。当我们进行算术运算时,将操作数放在俩个寄存器中,并将结果放到另一个寄存器中。此外cpu还有一组维护寄存器来维护寄存器状态(status),记录寄存器的移位,溢出等等。如果OS发现寄存器的状态被标记,则会识别出问题(比如除0溢出等)。OS会立刻发送硬件错误的信号给进程。将task_struct位图上的对应位置为1,调用指针数组的方法。

 

野指针

访问变量必须通过页表,建立地址空间和物理内存的映射关系。

而实际上在这个映射过程还必须通过MMU硬件的处理,来完成映射访问。

要进行访问时,会给出地址空间的地址,通过MMU计算内存地址。

既然MMU是硬件单元,必要会记录硬件状态,当我们要访问不属于我们的虚拟地址时,MMU的转化会失败,并写入状态信息。OS会识别到,并发送信号。


由软件引起的信号

介绍alarm闹钟函数

unsigned int alarm(unsigned int seconds);

指定时间后,OS向进程发送一个信号SIGALRM

操作系统就是一个进程,C如何理解OS的执行

OS本身就是一个死循环,操作系统的执行是基于中断的。

在硬件的底层 有CMOS,CMOS是高频率的,周期性的,向CPU发送时钟中断

OS通过COMS向CPU发送高频的闹钟信号,每一次接收到信号,CPU通过中断信号向量表 调度执行方法,所以只要调度得好,就能完成所有任务。

所以alarm函数就是最基本的软件产生信号。


小话题:核心转储

【 Linux 】信号的产生_第11张图片

有些信号的Action是Core核心

对于Core行为的信号,OS会将核心代码进行核心转储(将内存中的数据,全部dump到磁盘中)

会在当前路径下生成core.pid的二进制文件。

ulimit -a //查看特定的资源

【 Linux 】信号的产生_第12张图片

设置core资源的大小

ulimit -c 4096 //设置大小

【 Linux 】信号的产生_第13张图片

core只针对当前的shall端,且云服务器默认不开启

因为核心转储会消耗太多的空间。

常用于gdb的异常调试

你可能感兴趣的:(linux,linux,服务器,信号)