【Linux】:信号(三)捕捉

信号捕捉

  • 一.sigaction
    • 1.基本使用
    • 2.sa_mask字段
  • 二.可重入函数
  • 三.volatile
  • 四.SIGCHLD信号

承接上文

在这里插入图片描述

果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 用户程序注册了SIGQUIT信号的处理函数sighandler。 当前正在执行main函数,这时发生中断或异常切换到内核态。在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是 两个独立的控流程。sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了。

一.sigaction

1.基本使用

前面已经聊过signal函数了,这里就不再赘述。

+

在这里插入图片描述

第一个参数是传入的信号种类。

第二个和第三个参数都是struct sigaction类型结构体,前面一个是输入型参数,代表你要执行的动作;后一个是输出型参数,会把原本的信息带出,方便之后恢复。

返回值:成功返回0,失败返回-1.

例子

在这里插入图片描述

在这里插入图片描述

前面我们说过信号在发送后,操作系统会把pending位图的该信号位置置1,当处理该信号时将位图置零,然后执行方法。那么究竟是先置零再执行方法,还是方法执行完成后再置零呢?

在handler方法里打印pending图,即可看出先后顺序

在这里插入图片描述

在这里插入图片描述

从结果看出,操作系统是先将pending位图置零,再调用方法。

2.sa_mask字段

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

总之就是防止信号进行嵌套调用。

对比实验,一般情况下如果我们一直发2号信号,那么在处理2号信号时,其他2号信号一直会阻塞,pending图对应位置为1

在这里插入图片描述

在这里插入图片描述

在调用2号信号时同时屏蔽3号信号

在这里插入图片描述

在这里插入图片描述

二.可重入函数

例子:链表头插

在这里插入图片描述

一个链表进行头插时(不带哨兵节点)分为两步,先是p->next=head,接着是head=p。那么当代码执行到第一步时,突然接收到信号,而跑去进行信号中断了(这里并没有调用系统函数为什么能够实现内核态和用户态的转变从而进行信号中断呢?因为操作系统同时会执行多个进程,而为了让这些进程同时都被执行,操作系统会来回切换这些进程,从而不断的进行用户态和内核态的转变)。正巧我们对该信号的捕捉方法也是使用insert进行头插,那么程序就会再让另一个节点指向head。接着信号处理完毕,再返回继续执行第二步head->p。对于这种一个函数被重复调用的情况被称为函数重入。

以上就出现了问题,虽然node1节点插入成功了,但我们丢失了node2节点,从而导致了内存泄漏。

如果一个函数,被重复进入的情况下可能出错,那么就被叫做不可重入函数。否则就被叫做可重入函数。(目前的大部分函数都是不可重入的)

三.volatile

核心作用:防止编译器过度优化,保存内存可见性。

一个例子

在这里插入图片描述

在这里插入图片描述

这里的原理很简单,发送2信号后改变flag的值就不再死循环,但由于我们并未对flagj进行其他使用,如果我们启用编译器的优化功能会发生不同的现象。

在这里插入图片描述

常见的优化是O0~O3,这里使用O1优化。

在这里插入图片描述

在这里插入图片描述

可以看到我们发送了信号2后程序也并没有结束循环。这是为什么呢?

在这里插入图片描述

为了防止出现变量的过度优化,我们就可以使用volatile。

在这里插入图片描述

在这里插入图片描述

四.SIGCHLD信号

进程一章讲过用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞了就不能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一下,程序实现复杂。

其实,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程 终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。

在这里插入图片描述

验证

在这里插入图片描述

在这里插入图片描述

所以在进行进程等待时,我们可以采用基于信号的方式等待。

在这里插入图片描述

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

在这里插入图片描述

平常我们创建子进程后并没有主动释放但也并没有影响,因为Linux默认把17号信号设置成了SIG_IGN。

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

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

相关文章

MOS管的静电击穿问题

MOS管输入电阻很高,为什么一遇到静电就不行了? 静电击穿:由于静电的积累导致电压超过了原本MOS的绝缘能力,导致电流突然增大的现象。 MOS管基础知识了解: G极(gate)—栅极,不用说比较好认 S极(source)—源…

基于SSM框架的餐馆点餐系统的设计

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…

2023年亚太杯数学建模A题——深度学习苹果图像识别(

Image Recognition for Fruit-Picking Robots 水果采摘机器人的图像识别功能 问题 1:计数苹果 根据附件 1 中提供的可收获苹果的图像数据集,提取图像特征,建立数学模型,计算每幅图像中的苹果数量,并绘制附件 1 中所有…

【Java 基础】13 异常

1.异常是什么 异常是指在程序运行过程中可能发生的、与正常执行流程不符的事件。这些事件可能包括错误、不合理的输入、资源不足等。在 Java 中,异常是通过 throw 语句抛出的,可以是 Java 内置的异常类,也可以是自定义的异常类。 2. 异常类…

阅读文献总结2023

阅读文献基于卷积神经网络多源融合的网络安全态势感知模型 阅读文献 基于卷积神经网络多源融合的网络安全态势感知模型 题目基于卷积神经网络多源融合的网络安全态势感知模型文章信息:年份2023发文单位山西财经大学收录刊会计算机科学 (北大核心&#…

多线程(初阶五:wait和notify)

目录 一、概念 二、用法 (1)举个栗子: (2)wait和notify的使用 1、没有上锁的wait 2、当一个线程被wait,但没有其他线程notify来释放这个wait 3、两个线程,有一个线程wait,有一…

c++ pcl出现LNK2019 宏定义 PCL_NO_PRECOMPILE

问题:c pcl使用拟合圆柱时出现LNK2019问题; 说明:lib等配置没有问题; 解决方案 在上述代码中添加如下代码即可 #define PCL_NO_PRECOMPILE 是 C 中的预处理器指令,用于在代码中定义一个宏。而 #undef PCL_NO_PRECOM…

springBoot3.2 + jdk21 + GraalVM上手体验

springBoot3.2 jdk21 GraalVM上手体验 SpringBoot2.x官方已经停止维护了,jdk8这次真的得换了🤣 可以参考官方文章进行体验:https://spring.io/blog/2023/09/09/all-together-now-spring-boot-3-2-graalvm-native-images-java-21-and-virt…

C++基础 -25- 动态多态

静态多态在程序编译的时候,确定将要执行的状态。 动态多态在程序运行的时候,才能确定执行的状态。 下面举例实现动态多态 work函数接口通过传参不同做不同的工作 #include "iostream"using namespace std;class person {public:person(){}vi…

记一次移动云不同机器下的对等网络使用

1、清单 机器1的VPC: 子网:172.16.16.0/24 机器2的VPC 子网:172.27.27.0/24(子网不能与机器1的子网相同,否则对等网络无法成功建立) 2、添加对等网络 添加链接:https://console.ecloud.1008…

数字电源为什么一般用DSP控制,而不能用普通的单片机?

数字电源为什么一般用DSP控制,而不能用普通的单片机? 首先你要清楚,数字电源需要一个芯片具备什么功能? 1 能发PWM波 ,并且具备保护关断功能; 电源对PWM发波 要求很高,精度要ns级甚至ps级的&…

js数组方法大全(开发必会)

前言 js中数组的方法还是有很多的,而且js中数组操作方法我说是一个前端开发必须熟练使用和掌握的我想没有人反对吧。 说真的,数组这些api本身还是需要死记硬背的,就像乘法口诀表,很多东西你需要很熟练的就能写出来。就像让你去找数组里面符合条件的元素,你总可能定义一个空数…

docker部署kerberos,群晖nas中nfs开启kerberos校验

背景 nas开启nfs存储共享,默认情况下只能给IP/24做限制, 达不到安全效果 需要增加kerberos策略校验,并且持久化kerberos数据,避免容器重启丢失数据 环境描述 宿主机系统:CentOS Linux release 7.9.2009 (Core) Docker版本&#xf…

7nm项目之顶层规划——01数据导入

1.创建workspace 创建workspace后,在其目录下产生。 CORTEXA53.json文件是将有默认配置的文件master.json、有library的.config.json文件、tunes下CORTEXA53.tunes.json文件合并 注:tunes下的CORTEXA53.tunes.json文件可以覆盖一些master.json的设置…

学习感悟一己之言

学习感悟一己之言 学习上克服困难实际上是克服心理上或认识上的障碍的过程。所谓的理解,就是化陌生为熟悉。看不懂,一方面是因为接触的材料太陌生,即远离你当前的背景知识;另一方面是材料或讲述者的描述刻画不准确或晦涩不当。有了…

Halcon算子中的slant倾斜hom_mat2d_slant

1.hom_mat2d_slant(HomMat2DIdentity, rad(50), y, 0, 0, HomMat2DSlant) --这个是选择20度和50度的。(0, 0)点对应的是左上角,50度就是让y轴产生有50度的倾角。 2.hom_mat2d_slant(HomMat2DIdentity, rad(60), x, 0, 0, HomMat2D…

【Python表白限定】李峋同款可写字版跳动的爱心(完整代码)

文章目录 跳动的爱心环境需求完整代码详细分析系列文章 跳动的爱心 环境需求 python3.11.4PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库用于打包,使程序没有python环境也可以运行,如果想发给好朋友的话需要这…

RocketMQ-快速实战

MQ简介 MQ:MessageQueue,消息队列。是在互联网中使用非常广泛的一系列服务中间件。 Message:消息。消息是在不同进程之间传递的数据。这些进程可以部署在同一台机器上,也可以分布在不同机器上。(数据形式&#xff1a…

【C++笔记】红黑树封装map和set

一、map和set的泛型封装逻辑 map和set的底层都是红黑树,所以我们想要用红黑树封装map和set的第一个问题就来了,因为set是key结构而map是key-value结构,怎样用同一个底层结构去封装出两个不同存储结构的容器呢?难道我们要将红黑树…

git的版本控制流程

1、git是一款版本控制工具 例如我们常用的淘宝,每次升级,版本号就会加一。那么我们怎么控制版本号呢? --使用git。 2、最常使用的git指令 git add . 暂存 git commit -m"***" 提交到本地 git pull 将远程仓库代码下拉到本地 git …