linux信号的概念

目录

1.预备

2.信号如何产生

1.引入

2.原理

3.总结

3.接口

1.singal函数

2.kill函数

3.raise函数(给自己发信号)

4.abort函数(给自己发送6号信号)

4.异常

1.现象

2.原理

5.core和term区别

6.由软件条件产生信号

3.信号如何保存

1.原理

2.接口

3.代码运用

4.信号的处理

1.信号是什么时候被处理的?

1.重新谈地址空间:

2.操作系统的本质

3.用户态和内核态的切换


1.预备

1.进程必须能够识别+处理信号,也要具备处理信号的能力,这是属于进程内置功能的一部分。

(也就能说明进程即便没有收到信号,也知道哪些信号是如何被处理的!)

2.当进程真的收到这个信号,进程可能并不会立即处理这个信号。

3.当一个信号产生到信号开始被处理,就一定会有时间窗口,进程具有临时保存信号以及哪些信号被处理的能力

2.信号如何产生

1.引入

ctrl+c为什么能够杀死我们的进程?本质是接受到了我们的2号信号:

我们一般只用到前31的信号,称为普通信号(有时间窗口,不一定收到信号后要立即处理,可存储一定时间)。后面的信号是实时信号,就是收到就要理科处理的信号。

但是如果我们./process & 

linux中,一次登陆中,一个终端一般会配上一个bash,每一个登陆,只允许一个进程是前台进程,可以允许多个进程是后台进程----相当于只有前台进程可以获取键盘的输入。

2.原理

键盘是如何输入给内核的?ctrl+c又是如何变成信号的?

键盘被摁下,肯定是OS先知道的,那OS怎么知道键盘上有数据了?cpu不可能不停的就去检测键盘,有没有去写东西给文件,这样太浪费。而是键盘写入文件时,直接给cpu发送中断,(根据冯诺依曼结构说,cpu不可以直接访问键盘文件,但是键盘可以给cpu发送数据,因为cput上面有很多引脚,是直接连接这cpu的)然后cpu通过接送到的数据到内存的中断向量表中寻找读取键盘的方法,然后将键盘上的数据读取到键盘(文件)的缓冲区中,然后就是read等函数的事情了!

3.总结

信号产生的方式:无论信号如何产生最终一定是谁发送给进程的?OS!为什么?OS是进程的管理者!

3.接口

1.singal函数

第二个handler就是函数指针,实现接受到该信号的时候,进程该做什么。(但是并不是所有的信号都可以被修改)

这样我就可以通过这个函数中的ctrl是不是产生2好信号!

 就有人好奇了?在signal函数的第一个参数就知道是几号信号了!为什么函数指针要加这个参数,因为这个函数指针不一样只代表一个信号的函数指针,里面可能有其他信号的处理方式switch函数方式!

前31个信号只有9号和19号信号是不能通过signal改变,因为一个是杀死进程和暂停进程,如果可以修改的话,那病毒一些东西不就可以执行了吗?

2.kill函数

3.raise函数(给自己发信号)

ctrl + \相当于3号信号

4.abort函数(给自己发送6号信号)

可以看出abort()函数里面不仅有6号的信号!

4.异常

1.现象

但是如果我们通过signal函数修改改信号:

2.原理

而每次调度改进程,该溢出标志位都是1,OS就会发送给pcb中断信号,但是我们自己设计的信号处理方式没有退出,然后就调用其他进程,再次调用该进程时,还是会这样,所以只能死循环!

其实野指针也是一样的:

但是OS是如何识别是溢出还是访问越界呢?其实就是寄存器的不同给OS识别的!

上面这两个都是cpu硬件产生异常,给OS识别到的,有没有软件条件?---管道

但不是所有的异常都会将进程给杀掉:

5.core和term区别

man 7 signal  :

还记得父进程要等待子进程结束的waitpid函数吗?
进程等待-wait和waitpid-CSDN博客

而这上面的core dump就和这个有关!

可是core dump都是0啊,其实和下面有关:

可以将其修改(你如果再改回去,再改的话就不可以,应该是OS不允许这么随意修改吧。)

打开系统的core dump功能,一旦进程出异常,OS会将进程在内存中的运行信息,给我dump(转储)到进程的当前目录(磁盘)形成core.pid文件:核心转储(core dump)

而该core.pid文件可以存储哪一行代码出问题了:

可为什么系统要将这个core给删除掉呢?其实你看到到core.pid文件的大小便会明白了,很大。就想异常一开始的现象,如果一直像那样死循环,那整个系统岂不是可能会崩掉?得不偿失!

6.由软件条件产生信号

SIGPIPE是一种,SIGALRM也是一种:

也可以让他一直发送:

返回值:当一个alarm函数没有到时间,但收到了该信号,返回的就是上一个alarm还剩下多少秒。

3.信号如何保存

1.原理

基础概念:

在进程task_struct结构中存在两个整数,一个数组,block和pending自然是整形,用位图来表示每个信号的。block就是是否屏蔽某个信号,pending则表示是否收到该信号,handler就是收到该信号的处理方法!其中SIG_DFL(default)就是默认处理方法,SIG_IGN(ignore)就是忽略的处理方法,User Space就是自定义了。

一样和上面myhandler一样是函数指针:

2.接口

上面得知这些信号存储在位图中,操作系统肯定不会让我们直接去改变位图的,因为操作系统不相信我们,这肯定的!所以,就提供给我们一个结构体,然后通过函数来初始化他们!

当运用玩这些函数,至此对操作系统的信号位图是一点都没有触碰到呢!

相当于修改上面的block的位图:

int how:SIG_BLOCK(增加该信号屏蔽他,mask = set | mask)SIG_UNBLOCK(删除,mask = mask & ~set, SIG_SETMASK,直接覆盖)

oldset则是修改前set拷贝给oldset。

获取当前pending中的位图,再运用的上面的sigismember函数就能得知该进程是否接受到了该信号了!

改变信号的处理方法,上面已经说过了:signal

3.代码运用

一样,如果全屏蔽掉,那岂不是不能收到信号?和上面一样9和19好信号不可以收到!

4.信号的捕捉

1.信号是什么时候被处理的?

       当我们的进程从内核态返回到用户态的时候,进行信号的检测和处理。(比如:调用系统调用--操作系统是自动会做“身份”切换的,用户身份变成内核身份,或者反着来;int 80 从用户态陷入内核态(下面会说))

1.重新谈地址空间:

用户页表:有几个进程,就有几个用户级页表---进程具有独立性

内核级页表:只有1份

每个进程看到的3-4GB(内核空间)是一样的,整个系统中,进程再怎么切换,3,4GB空间的内容是不变的!!!

进程视角:我们调用系统中的方法,就是在自己的地址空间中执行的。

操作系统视角:任何一个时刻,都有进程执行。我们想执行操作系统的代码,可以随时执行。

2.操作系统的本质

基于时钟中断的一个死循环。

其实我们应该想过,我们修改这些位图的信号,那进程怎么知道的?OS告诉它的,那OS又怎么知道的?

计算机硬件中,有一个时钟芯片,每个很短的时间,向计算机发送时钟中断!

3.用户态和内核态的切换

但是有人回想,那我们正常程序,就打印点东西,循环,不用系统调用函数,也进入不了内核态啊。cpu在运行进程时是一个一个进程单独运行的,不可能同时运行两个进程,所以进程都是先跑一会,给其他进程跑一会。当这个进程第二次被调度时,从就绪队列转换成运行队列,操作系统把该进程的PCB,寄存器,页表等等放到cpu上,则肯定时内核态,但是运行你普通代码时,肯定是用户态----这不是转换了嘛!

2.sigaction函数

act和oldact和上面一样,act是你要改变该信号的处理的结构体,oldact是上一个状态的结构体。

问题1: pending位图,什么时候从1->0. 执行信号捕捉方法之前,先清0,在调用

问题2: 信号被处理的时候,对应的信号也会被添加到block表中,防止信号捕捉被嵌套调用

用代码解决疑惑:

sa_handler和signal中的handler一样是修改该信号的处理方式:


sa_mask:是当我们处理某个信号时,我们还可以屏蔽其他信号:

当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来 的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止。 如果 在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需 要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。

3.可重入函数

向上例这样,insert函数被不同的的控制流程调用,有可能在第一次调用还没有返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为冲入而造成错乱,像这样的函数称为不可重入函数,反之,如果一个函数只访问自己的局部变量或者参数,则称为可重入(Reentrant)函数。

如果一个函数满足一下条件之一则是不可重入的:

1.调用了malloc或者free,因为malloc也是用全局链表来管理堆的。

2.调用了标准I/O库函数,标准I/O库的很多实现都是以不可重入的方式使用全局数据结构。

其实要知道main的栈和信号处理的栈不是同一个栈,即不是同一个执行流。下面也有涉及这个知识。

4.从信号的视角来看volatile

正常情况下是退出的:

但是g++可以在编译时进行优化:发现在main的执行流中flag是不发生改变的,所以优化到了寄存器中:想想register类似,但不一样,这个修饰过依旧可以修改这个变量。

g++如何优化呢?优化分几个等级:man g++  ------ 在进入后/-o1搜索

在-o2之后都可以了:


这也就说明信号中处理flag是处理的内存中的flag了,与那个寄存器flag无关了,也就侧面说明main和信号处理函数不在同一个栈中!

vloatile关键字:防止编译器过度优化,保持内存的可见性!

5.SIGCHLD信号

我们在学习waitpid时,是在等待子进程,防止子进程一直处于僵尸状态,而导致内存泄露,但是每当子进程退出时,其实子进程都会发给父进程一个信号SIGCHLD:所以我们可以修改该信号处理方式,在函数里里面回收子进程,将会更加方便:

但是我们可以直接让子进程退出后,让操作系统回收:
signal(SIGCHLD, SIG_IGN);

但是我们注意到17信号的处理方式就是ign忽略啊,其实我没想到操作系统的是signal(17, SIG_DFL)里面可能有DFL->action(让进程僵尸)->IGN:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/539878.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统搭建DataEase并结合内网穿透实现任意设备公网查看本地数据

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-HLq7cU4G5of6W4QU {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

Wmware安装Linux(centerOS、Ubuntu版本)

目录 1、安装wmware 2、center版本 3、ubuntu版本 1、安装wmware 此处不做展开。 2、center版本 需要提前下载的文件: 无图形化界面https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso 有图形化界面https://mirrors.a…

javaEE11(servlet课后习题1,3(将思路实现一下))

1.在第5章课后习题2基础上,基于jspservletjavabean实现学生表的增删改查。 数据处理交给Servlet package servlet;import java.io.IOException;import java.io.PrintWriter;import java.util.List;import javax.servlet.ServletException;import javax.servlet.an…

操作系统(多线程)

1.概述 每个线程是CPU使用的一个基本单元,包括线程ID、程序计数器、寄存器组和堆栈。 传统单线程: 多线程进程: 2.动机 在某些情况下,单个应用程序可能需要执行多个类似的任务。例如,一个Web服务器接受有关网页、图像…

网络安全,硬防迪云

要减少被攻击的频率,游戏开发者可以采取以下措施: 1. 强化安全措施:确保游戏服务器和用户数据的安全性,加密网络传输,防止黑客攻击和数据泄露。 2. 更新和修复漏洞:定期检查游戏代码和服务器,…

《ElementPlus 与 ElementUI 差异集合》el-input 和 el-button 属性 size 有变化

差异 ** element-ui el-input、el-input-number 和 el-button 中,属性size 值是 medium / small / minielement-plus el-input、el-input-number 和 el-button 中,属性size 值是 large / default /small 如果你是自动升级,Vue3 系统会有如…

Redis的内存淘汰策略是怎么样的?

淘汰策略 Redis 的内存淘汰策略用于在内存满了之后,决定哪些 key 要被删除。Redis 支持多种内存淘汰策略,可以通过面置文件中的 maxmemory-policy 参数来指定。 以下是 Redis 支持的内存淘汰策略 noeviction:不会淘汰任何键值对,而是直接返…

全新升级SQLCoder-7B-2:领先的自然语言至SQL转换模型,性能显著提升

前言 随着数据科学和机器学习技术的不断进步,自然语言处理(NLP)已成为连接人类语言和计算机编程之间的重要桥梁。在这个交汇点上,SQLCoder-7B-2模型的最新升级引领了一场革命,特别是在自然语言至SQL生成方面&#xff…

Java代码基础算法练习---2024.3.14

其实这就是从我学校的资源,都比较基础的算法题,先尽量每天都做1-2题,练手感。毕竟离我真正去尝试入职好的公司(我指的就是中大厂,但是任重道远啊),仍有一定的时间,至少要等我升本之后…

unity3d Animal Controller的Animal组件中Speeds,States和modes基础部分理解

Speeds 速度集是修改你可以做的原始动画,增加或减少运动,旋转,或动画速度。它们与 州 所以,当动物在运动状态下,在飞行或游泳时,你可以有不同的速度 如果你的性格动画是 (已到位), 你一定要调整速度 位置 和 旋转 每一种的价值观 速度装置 …否则,它们不会移动或旋转。 每个速…

Day42-企业级网络存储NFS01

Day42-企业级网络存储NFS01 1. 什么是NFS?2. 为什么要用网络共享存储?3. 共享存储的种类4. NFS工作原理5. 环境准备6. NFS软件列表7. 安装8. 配置nfs9. 项目实践作业:10. ()权限 对应参数11. 在生产中配置NFS的重要技巧:12. 项目实…

windows 11访问Debian10上的共享目录

步骤 要在Windows 11上访问Debian 10.0.0的共享目录,可以通过以下步骤来实现: 1. 设置Samba服务:在Debian系统上,需要安装并配置Samba服务,以便能够实现文件夹共享。Samba是一个允许Linux/Unix服务器与Windows操作系…