Linux信号补充——信号捕捉处理

一、信号的捕捉处理

​ 信号保存后会在合适的时间进行处理;

1.1信号处理时间

​ 进程会在操作系统的调度下处理信号,操作系统只管发信号,即信号处理是由进程完成的

​ 1.信号处理首先进程得检查是否有信号;2.进程要处于内核状态才能处理信号;

即进程会在内核态返回用户态的时候检查并处理信号

在这里插入图片描述

​ 对于程序的执行有一部分是自己写的,有一部分是库提供的,还有一部分是操作系统提供的;执行操作系统提供的代码需要进行身份的切换,执行自己写的和库提供的一般是以用户态的身份执行,执行系统调用,或者是进入操作系统内部(如硬件中断,根据中断号执行内核的终端表方法)需要以内核态的身份进行;

​ 操作系统可以响应外部硬件的中断,也可以响应内部软件产生的中断;int 80(是一条汇编也是CPU可以认识的指令)就是一种软件中断,功能是让进程从用户态陷入内核态;

​ 总结:程序运行时,会从代码区开始执行,执行到函数调用时触发int 80将ecs后两位由11变成00,进入内核态,根据用户级页表映射进入内核空间执行代码,根据内核级页表映射到内存空间,执行代码,返回时要先执行一次do signal(当前进程对信号做一次检测,对pending表,block表的检测),如果不需要处理,直接变成用户态,将ecs寄存器的后两位由00变成11,并且返回到原先用户空间执行代码处;否则先将pending表对应信号位置零,对于忽略方式直接返回,默认方式直接执行,都是在内核空间处理,而对于自定义处理需要先将身份转换为用户态(因为操作系统不信任用户的代码,有风险)然后执行完使用sigreturn(使用函数压栈的方式传入的此函数,所以可以执行)返回内核态跳转之前的位置,然后在跳转回用户态执行的地方;

​ 要注意main和sighandler是两个不同的执行流不是调用和被调用的关系;

在这里插入图片描述

​ 对于自定义信号处理进行了4次身份切换,两次信号的检测,而默认和忽略方式处理信号只是进行了2次身份切换,1次信号检测;

​ 由于进程是会被调度的,进程上下文的恢复和进程调度的实现都是在内核空间的,所以一定会由频繁的身份切换,所以一定会对信号进行检测;

1.2信号处理接口

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
//既可以处理普通信号也可以处理实时信号
struct sigaction {
    void     (*sa_handler)(int);
    void     (*sa_sigaction)(int, siginfo_t *, void *);//不关心,处理实时信号
    sigset_t   sa_mask;//,除了当前信号自动屏蔽,还可以选择将多个信号屏蔽
    int        sa_flags;//不关心,默认设为0
    void     (*sa_restorer)(void);//不关心
};
//与signal使用类似只不过需要传入结构体对象;

​ 信号处理前会先将pending位图对应位置的1置为0;

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

上述方式可以防止信号捕捉函数被重复调用

二、补充话题

2.1可重入函数

​ 当头插节点时,有三个位置newnode1,prev,cur三个节点指针,刚完成刚完成newnode1和cur节点的链接,还没有执行prev和newnode1的链接,因为信号的处理跳转到新的执行流,刚好信号处理也是头插,使用的是newnode2,这次执行是完整的,返回用户态是继续执行会将指向newnode2的prev指向了newnode1,这样会导致newnode2丢失导致内存泄漏;

​ 如上现象就是函数被重入了,对于函数如果重入了出错,则该函数就是不可重入函数,反之就是可重入函数;

​ 信号处理和main执行流并不是和多线程一样一旦创建线程执行流就开始运行,并且和main执行流是并行的,而是取决于信号并且执行信号流时会使得main执行流被暂停,是一个进程的不同执行流;

2.2volatile

​ volatile作用是保持内存可见性;进行运算(算术运算或者逻辑运算),都会进入CPU的运算器进行;

​ 在优化条件下如果只是对变量读取不进行修改,可能变量会被优化到寄存器里面,而不是内存中,这样优化是的不需要进行访存,提高了效率;

​ 如:设置全局变量,main执行流只是进行了读取,而信号执行流进行了写入,这时候编译器优化,main执行流不从内存中读取,而是从寄存器读取,但是寄存器中的内容并不会被修改,信号执行流进行了写入,内存中实实在在的被修改了;这时候就会导致全局变量即使被修改了,但是main在执行流不可见;所以需要在全局变量前加volatile关键字修饰,保持内存的可见性,使得main执行流从内存中进行读取;

register是一个建议性关键字用来进行优化,还是会创建变量,但是可能会将变量内容放到寄存器;

2.2.1Linux gcc/g++优化

gcc -O .c文件
#选项包括-O0到-O3;0表示没有优化,1-3从低到高进行优化;

2.3SIGCHID

​ 子进程退出时,父进程必须进行等待,否则子进程就会变成僵尸状态;

​ 等待的目的:1.使得子进程可以被回收;2.获得子进程的退出信息;3.由于子进程的退出是未知的,所以父进程需要阻塞或者是非阻塞的方式进行等待,要保证父进程是最后一个退出的;

子进程并不是直接就退出了,而是会向父进程发送信号的;此信号就叫做SIGCHID(17号)信号

​ 进程等待可以采用基于信号的方式实现异步等待;要保证父进程在这期间是一直运行的;

​ 使用waitpid非阻塞的方式或者是基于信号的等待都可以使得父进程继续运行,不用阻塞;

​ 关于多个子进程等待,使用-1来接受任意多个子进程,使用WNOHANG防止等待时,有进程不退出导致阻塞;

​ 对于信号实现子进程的等待也可以不调用waitpid;事实上,由于UNIX的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略通常是没有区别的,但这是一个特例。此方法对于Linux可用,但不保证在其它UNIX系统上都可用;

​ 17号信号的默认处理方式是忽略,而忽略方式是自动清理子进程;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

双指针(对撞指针、快慢指针)

本博客将讲述OJ题中的常用的双指针 双指针的含义 双指针算法是一种常用的算法技巧&#xff0c;它通常用于在数组或字符串中进行快速查找、匹配、排序或移动操作。 双指针并非真的用指针实现&#xff0c;一般用两个变量来表示下标&#xff08;在后面都用指针来表示)。双指针算…

QML TextField 默认无法鼠标选中内容

1.import QtQuick.Controls 2.0 后的TextField默认无法选中内容如下图&#xff1a; 2.增加属性设置 selectByMouse: true 可以选中内容了 TextField{ selectByMouse: true text:"1234567890987654321" } 效果如下:

多线程(JUC, ReentrantLock, 原子类, 线程池, 信号量 Semaphore, CountDownLatch)

JUC Java.util.concurrent 包, 存放了并发编程相关的组件, 目的是更好的支持高并发任务 (多线程只是实现并发编程的一种具体方式 …) ReentrantLock 可重入互斥锁, 和 synchronized 定位类似, 用来实现互斥效果, 保证线程安全. synchronized 对对象加锁, 保护临界资源Reentreat…

面向量产!基于视觉的速度距离估计

面向量产&#xff01;基于视觉的速度距离估计 论文名称&#xff1a;Vision-based Vehicle Speed Estimation: A Survey 导读 在精确检测车速车距的方案中&#xff0c;视觉方案是非常具有挑战性的&#xff0c;但由于没有昂贵的距离传感器而大幅降低成本&#xff0c;所以潜力巨…

【现代C++】范围基于的for循环

现代C中的范围基于的for循环&#xff08;range-based for loop&#xff09;是C11引入的一项特性&#xff0c;旨在简化对容器或范围的迭代过程。这种循环语法不仅使代码更清晰易读&#xff0c;还减少了迭代时的错误。以下是范围基于的for循环的详细介绍&#xff1a; 1. 基本用法…

Vue3的与2的简单区别

Vue2选项式api Vue3组合式API setup方法的使用&#xff0c;最后需要return setup语法糖省略了内部的export default{} 和return 内容 以及组件的注册 reactive生成响应式对象&#xff0c;只能适用于复杂对象&#xff0c;简单类型不可 ref生成响应式数据&#xff1a;复杂类型和简…

leetcode 数组练习,美团优选面试题java

public int maxSubArray(int[] nums) { int countnums[0]; int resnums[0]; for(int i1;i<nums.length;i){ if(count<0){ countnums[i]; }else{ countnums[i]; } resMath.max(res,count); } return res; } 3、两数之和 利用map,来存储数组值和当前位置&…

【Review】电动汽车百人会

汽车强国靠四化--电动化、智能化、低碳化、全球化。 1.坚持电动化&#xff1a;电动化是经过二十多年反复论证的既定战略和技术路线、不能动摇、无需改变、要将电动化进行到底&#xff0c;全力攻克下一代电动化核心技术--全固态锂电池;市场方面要采用“双轮”驱动战略一方面继续…

基于PID控制器的四旋翼无人机控制系统的simulink建模与仿真,并输出虚拟现实动画

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1四旋翼无人机的动力学模型 4.2 PID控制器设计 4.3 姿态控制实现 4.4 VR虚拟现实动画展示 5.完整工程文件 1.课题概述 基于PID控制器的四旋翼无人机控制系统的simulink建模与仿真,并输出vr虚拟现实…

政安晨:【深度学习实践】【使用 TensorFlow 和 Keras 为结构化数据构建和训练神经网络】(四)—— 过拟合和欠拟合

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 通过增加容量或提前停止来提高性能。 在深度学习中&#…

Springboot 整合 Knife4j (API文档生成工具)

目录 一、Knife4j 介绍 二、Springboot 整合 Knife4j 1、pom.xml中引入依赖包 2、在application.yml 中添加 Knife4j 相关配置 3、打开 Knife4j UI界面 三、关于Knife4j框架中常用的注解 1、Api 2、ApiOperation ​3、ApiOperationSupport(order X) ​4、ApiImplici…

C# WPF编程-布局

C# WPF编程-布局 布局WPF布局原则布局过程布局容器布局属性Border控件StackPanel布局WrapPanel布局DockPanel布局Grid布局UniformGrid布局Canvas布局 布局 WPF布局原则 WPF窗口只能包含单个元素。为在WPF窗口中放置多个元素并创建更贴近实用的用户界面&#xff0c;需要在窗口…

linux系统----------MySQL索引浅探索

目录 一、数据库索引介绍 二、索引的作用 索引的副作用 (缺点) 三、创建索引的原则依据 四、索引的分类和创建 4.1普通索引 4.1.1直接创建索引 4.1.2修改表方式创建 4.1.3创建表的时候指定索引 4.2唯一索引 4.2.1直接创建唯一索引 4.2.2修改表方式创建 4.2.3创建表…

根据log信息解读内核(linux-2.6.32.24)的启动流程

目录 概述 1 从bootloader 到内核部分 2 初始化cache和CPU时钟 3 获取cache和memory信息 4 初始化cache、电源管理和中断 5 初始化USB和I2C 6 网络协议初始化 7 挂载JFFS2文件系统和初始化IO 8 初始化外围device 9 Nand Flash资源分配 10 初始化网络接口 11 注册US…

一文快速掌握docker的理念和基本使用

写在文章开头 写于一个周末&#xff0c;在复盘梳理文章时候发现这一篇关于早期了解docker时记录的文档&#xff0c;仔细阅读了一下&#xff0c;为了保证文章更加清晰以便读者使用。故再次重新一次梳理一次&#xff0c;通过这篇文章&#xff0c;你将会对docker的基本理念和基础…

Expert Prompting-引导LLM成为杰出专家

ExpertPrompting: Instructing Large Language Models to be Distinguished Experts 如果适当设计提示&#xff0c;对齐的大型语言模型&#xff08;LLM&#xff09;的回答质量可以显著提高。在本文中&#xff0c;我们提出了ExpertPrompting&#xff0c;以激发LLM作为杰出专家回…

【C语言基础】:字符串函数(二)

文章目录 一、strncpy函数的使用二、strncat函数的使用三、strncmp函数的使用四、strstr函数的使用和模拟实现4.1 strstr函数的使用4.2 strstr函数的模拟实现 五、strtok函数的使用六、strerror函数的使用 上节回顾&#xff1a;【C语言基础】&#xff1a;字符函数和字符串函数 …

【ubuntu20.04+tensorflow-gpu1.14配置】

ubuntu20.04tensorflow-gpu1.14配置 目录0. 版本注意事项说明1. 个人目录下载后配置系统环境变量2. anaconda配置所有环境&#xff08;过程简便&#xff0c;但容易出现不兼容问题&#xff09;3. 验证tensorflow-gpu4. 一些细节 目录 总结出两种方法 个人目录 下载cuda和cudnn…

分库分表场景下多维查询解决方案(用户+商户)

在采用分库分表设计时&#xff0c;通过一个PartitionKey根据散列策略将数据分散到不同的库表中&#xff0c;从而有效降低海量数据下C端访问数据库的压力。这种方式可以缓解单一数据库的压力&#xff0c;提升了吞吐量&#xff0c;但同时也带来了新的问题。对于B端商户而言&#…

赋能智能未来:AI大模型的学习之旅

随着人工智能的迅速发展&#xff0c;AI大模型已经成为技术领域的一个热点。这些模型以其强大的数据处理能力和预测精度&#xff0c;正在不断推动着科技的边界&#xff0c;并且在医疗、金融、交通等多个行业中显示出了巨大的潜力。然而&#xff0c;构建和训练一个高效的AI大模型…