只说相关函数和理论 具体实现建议自行尝试或者详细文章 这里推荐下”一只大喵咪1201“
进程不会立即处理信号 不会立即处理的信号会先保存
处理信号:默认 自定义 忽略
信号时间顺序:信号产生-》信号保存-》信号处理
自定义信号
signal:更改信号处理方式
注意:9号信号不会被更改
信号的产生
键盘按键(产生的信号)
(热键)ctrl+c 结束进程 顾名思义 多说无益
函数调用系统调用(产生的信号)
就是调用函数比如kill abort等函数操作进程
硬件(产生的信号)
1.寄存器出问题 比如除零操作导致数据溢出 状态寄存器溢出标志位为一 操作系统得到一 让进程停止
2.访问内核指针
软件(产生的信号)
1.管道某一段关闭而另一端打开就属于
2.定时器(闹钟)
小节尾语
虽然很多信号最终结果都是停止 但不同名字的停止方便了解停止原因
信号保存
信号递达:处理信号
信号未决:刚产生准备处理(或不处理)
信号阻塞:保持未决
信号忽略:不处理该信号
信号保存在内核 有三个表处理不同的信号
pending:存放接收到信号 block:存放阻塞信号 handle:存放自定义信号的函数指针
前两个表是一个整形 有信号时更改比特位 最后一个是数组
对于这三个表也是有函数可以对其操作的
sigset_t:pending block
signal:handle
更详细的函数调用就请大家看这篇文章啦:
原文链接:https://blog.youkuaiyun.com/weixin_63726869/article/details/129843603
非可靠信号(自定义信号)只会添加一次在未决集合(pending) 可靠相反
同一个可靠信号多次添加到sigqueue链表中,这一个信号全部被处理完后,才会从pending集中移除
停止状态信号 僵尸进程 阻塞信号 自定义处理信号 不会被kill(强行终止 就是下面的SIGKILL)
SIGTOP SIGKILL无法被阻塞 无法被自定义 无法被忽略
信号处理
想要处理一个信号必须先捕获到信号 所以才会有下面身份的转换
用户态:执行用户代码时
内核态:访问内核资源或者硬件资源时
cr3寄存器:cpu中有很多寄存器 cr3寄存器用于存储进程状态(辨别当前进程状态)
0:内核态 3:用户态
处理过程:
用户态转 内核态转 用户态转 内核态转 用户态
(身份转换了四次 如果信号是默认处理和忽略啧两次):
中断/异常/系统调用---进入内核----》处理异常后处理信号-》两种情况
1.自定义信号:返回用户态根据自定义函数处理(保证安全)-》回到内核态找到上次中断位置-》继续读代码
2.默认信号:自行处理-》找到上次中断位置-》继续读代码
未决信号会从内核态返回用户态的时候处理
只有自定义处理信号会用户态处理 自定义处理信号信号捕捉后返回内核态(其实看明白上面的转化这两句就是废话)
中断/异常:整数除零 read系统调用 物理断电(拔电源hhh)
可重入函数:自己任务没完成被叫去执行另一个任务 不可重入相反
原子性:一次完成不可被打断操作 所以可以重入 可以对全局变量进行操作 局部不可
实现原子性以及注意问题
所谓原语的原子性操作是指一个操作中的所有动作,要么成功完成,要么全不做。也就是说,原语操作是一个不可分割的整体。
为了保证原语操作的正确性,必须保证原语具有原子性。在单机环境下,操作的原子性一般是通过关闭中断来实现的。
由于中断是计算机与外设通信的重要手段,关闭中断会对系统产生很大的影响,所以在实现时一定要避免原语操作花费时间过长,绝对不允许原语中出现死循环。