当前位置: 首页 > news >正文

【Linux】信号知识三把斧——信号的产生、保存和处理

目录​​​​​​​

1、关于信号的前置知识

1.1.什么是信号?

1.2.为什么要学习信号?

1.3.如何学习信号?

1.4.一些常见的信号

1.5.信号的处理方式

1.6.为什么每一个进程都可以系统调用?

2.信号的产生

2.1.kill命令产生信号

2.2.键盘产生信号

CTRL+c和CTRL+\的区别

2.3.调用系统函数向进程发信号

2.4.软件条件产生信号

2.5.异常产生信号(硬件异常)

2.6.信号产生的小总结

3.信号的保存

3.1三张表基础

阻塞vs忽略:

3.2三张表匹配的操作和系统调用

3.3.Core和Term

如何打开Linux的core功能呢?

为什么要用核心转储功能呢?

4.信号的处理

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

4.2.信号是如何被处理的?

4.3.volatile

1、关于信号的前置知识

1.1.什么是信号?

Linux系统提供的让用户(进程)给其他进程发送异步信息的一种方式。(注意信号和信号量这两者没有任何关系!)

举个例子:

用户输入命令,在Shell下启动一个前台进程。用户按下 Ctrl-C ,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程前台进程因为收到信号,进而引起进程退出~

进程就是你,操作系统就是快递员,信号就是快递

1.2.为什么要学习信号?

我们平时在处理进程的时候,对于停止、删除进程等操作,系统要求进程要有随时响应外部信号的能力,随后做出反应

1.3.如何学习信号?

根据进程对于整体信号的操作过程进行学习。

  1. 信号的产生(kill命令和键盘产生信号)
  2. 信号的保存
  3. 信号的处理

1.4.一些常见的信号

用kill -l命令可以察看系统定义的信号列表

数组和名字都可以标识一个信号,名字其实就是宏,注意没有信号0,没有信号32和33

1.5.信号的处理方式

  • 信号自己的默认动作
  • 自定义处理信号,捕捉信号
  • 忽略信号,忽略也代表处理过信号了

所以我们自己是可以更改对信号的处理方式。

1.6.为什么每一个进程都可以系统调用?

写时拷贝的时候拷贝的全部都是用户空间,不会拷贝内核空间

每一个进程都有自己的地址空间,多个进程就会有多个地址空间,但是内核空间只有一份。所以任何一个进程都可以系统调用

2.信号的产生

2.1.kill命令产生信号

当我们输入kill命令去给进程发送信号的时候,本质是OS进行操作的。

2.2.键盘产生信号

键盘如何产生信号呢?

常见的有CTRL+c,代表中断这个程序;CTRL+ \发送SIGQUIT信号给当前进程,导致该进程退出并生成core转储文件

CTRL+c和CTRL+\的区别

CTRL+\与Ctrl+C不同,后者只是发送SIGINT信号给当前正在运行的进程,导致进程被终止。Ctrl+\会生成core文件,这个文件包含了进程在退出时的内存映像,可以用于调试。如果进程成功生成core文件,那么可以使用调试工具来分析这个文件,以了解进程崩溃时的状态,这对于排查问题非常有帮助‌。

2.3.调用系统函数向进程发信号

kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。raise函数可以给当前进程发送指定的信号(自己给自己发信号)。

  • kill函数对任意进程发送任意的信号
  • raise函数对自己发送任意信号

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
这两个函数都是成功返回0,错误返回-1

abort函数使当前进程接收到信号而异常终止

#include <stdlib.h>
void abort(void);
就像exit函数一样,abort函数总是会成功的,所以没有返回值。

2.4.软件条件产生信号

alarm函数 和SIGALRM信号就是由软件条件产生信号的代表

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动
作是终止当前进程。

这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。如果参数seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数

2.5.异常产生信号(硬件异常)

  • 代码除零产生异常
  • 野指针异常

硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。

例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。

再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。

注意寄存器只有一个,但是寄存器的数据可以有很多,我们把寄存器中的数据叫做:上下文数据!!!

2.6.信号产生的小总结

当信号产生的时候,如果进程在处理更加重要的事情,我们就暂时不能处理到来的信号,我们必须暂时要将到来的信号进行临时保存。

那么问题来了,我们将这些信号保存在哪里呢?——进程的PCB中

所以只有OS才有资格写入信号,如果用户也想写入信号,就必须使用OS提供的系统调用。因此,无论信号产生的方式有多少种,最终都是OS亲自动手将信号写入进程的!!!

3.信号的保存

3.1三张表基础

理论上来说我们用3张表就可以保存信号

  • 实际执行信号的处理动作称为信号递达(Delivery)
  • 信号从产生到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (Block )某个信号
  • 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
  • 注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

阻塞vs忽略:

忽略是一种信号递达的方式。阻塞仅仅是不让指定信号进程递达

  • pending表比特位的位置,表示信号编号,比特位的内容,表示是否收到指定信号
  • block表的比特位的位置,表示信号编号,比特位的内容,表示是否阻塞该信号

下面这三张表需要我们横着读,最后一个handler表示对信号的处理方法

这三张表分别表示信号是否阻塞,信号是否接受到,信号的处理动作

所以我们看这张表的时候,不是竖着看,而是横着看每一个信号

3.2三张表匹配的操作和系统调用

block表对应的是sigprocmask函数

调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若出错则为-1

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则 更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

pending表对应的是sigpending函数

#include <signal.h>
sigpending
读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。

handler函数对应的是signal函数。

可以对指定的信号进行用户指定的信号处理。更改信号的处理方式。

下面是利用这几个函数进行编码,小试牛刀。 

3.3.Core和Term

大多数信号的默认响应行为都是Core或者Term;

这两种信号都表示终止进程

区别:

  • Term就是普通的终止进程,之后没有其他动作。
  • Core不仅会终止进程,还会生成一个核心转储文件

为什么默认关闭核心转储功能?防止未知的core dump 一直在进行,导致服务器磁盘被打满,所以默认core是关闭的。

如何打开Linux的core功能呢?

使用ulimit -a查看当前资源限制的设定 ;

其中,第一行显示core文件的大小为0,即表示核心转储是被关闭的

通过ulimit -c size 命令来设置Core文件的大小(同时也是打开了核心转储

为什么要用核心转储功能呢?

想通过core定位到进程为什么退出,以及执行到哪行代码退出的

核心转储功能是什么?

将进程在内存中的核心数据(与调试有关)转储到磁盘中形成。

有什么用呢?

协助我们进行调试!

4.信号的处理

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

合适的时候,什么是合适的时候呢?进程从内核态(操作系统的状态,权限级别高),切换到用户态(你自己的状态)的时候,信号会被检测并处理

在信号处理的过程(捕捉)中,一共会有4次的状态切换(内核和用户态)

4.2.信号是如何被处理的?

我们使用系统调用或者访问系统数据,其实还是在进程的地址空间内进行切换的

进程无论如何被切换,总能找到OS,我们访问OS,本质就是通过我们的进程的地址空间进行访问

4.3.volatile

volatile 作用:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作

 

编译器正常处理是将flag的值从内存读取到CPU中进行处理

当前编译器做了一个优化,因为系统认为flag的值定义之后就没有改变,因此直接将内存里flag的值直接放在了CPU 的寄存器中,因此后面代码改变flag值的时候,是在内存当中改变的,CPU中的值不会改变,而程序读取数据是从CPU读取的,因此就会造成偏差,这时候就需要我们的volatile去修饰这个变量,默认从内存中读取!​​​​​​​

相关文章:

【Linux】信号知识三把斧——信号的产生、保存和处理

目录​​​​​​​ 1、关于信号的前置知识 1.1.什么是信号&#xff1f; 1.2.为什么要学习信号&#xff1f; 1.3.如何学习信号&#xff1f; 1.4.一些常见的信号 1.5.信号的处理方式 1.6.为什么每一个进程都可以系统调用&#xff1f; 2.信号的产生 2.1.kill命令产生信号…...

【国庆要来了】基于Leaflet的旅游路线WebGIS可视化实践

前言 转眼2024年的国庆节马上就要来临了&#xff0c;估计很多小伙伴都计划好了旅游路线。金秋十月&#xff0c;不管是选择出门去看看风景&#xff0c;还是选择在家里看人。从自己生活惯了的城市去别人生活惯了的城市&#xff0c;去感受城市烟火、去感受人文风景&#xff0c;为2…...

Element-UI Plus 暗黑主题切换及自定义主题色

1. 暗黑主题切换 在main.js中引入下面文件 import element-plus/theme-chalk/dark/css-vars.css安装 vueuse/core pnpm add vueuse/coreApp.vue 添加下面代码 使用了 useDark() 的页面才会从 localStorage中读取当前主题状态&#xff0c;否则&#xff0c;刷新页面就会恢复默…...

人工智能与机器学习原理精解【31】

文章目录 卷积神经网络CNN定义数学原理与公式计算与定理架构例子例题 全连接层的前馈计算定义数学原理与公式计算过程示例 参考文献 卷积神经网络 CNN 即卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;&#xff0c;是一类包含卷积计算且具有深度结构的前…...

如何安全地大规模部署 GenAI 应用程序

大型语言模型和其他形式的生成式人工智能(GenAI) 的广泛使用带来了许多组织可能没有意识到的安全风险。幸运的是&#xff0c;网络和安全提供商正在寻找方法来应对这些前所未有的威胁。 随着人工智能越来越深入地融入日常业务流程&#xff0c;它面临着泄露专有信息、提供错误答…...

verilog实现FIR滤波系数生成(阶数,FIR滤波器类型及窗函数可调)

在以往采用 FPGA 实现的 FIR 滤波功能&#xff0c;滤波器系数是通过 matlab 计算生成&#xff0c;然后作为固定参数导入到 verilog 程序中&#xff0c;这尽管简单&#xff0c;但灵活性不足。在某些需求下&#xff08;例如捕获任意给定台站信号&#xff09;需要随时修改滤波器的…...

OSPF的不规则区域

1.远离骨干非骨干区域 2.不连续骨干 解决方案 tunnel ---点到点GRE 在合法与非ABR间建立隧道&#xff0c;然后将其宣告于OSPF协议中&#xff1b; 缺点&#xff1a;1、周期和触发信息对中间穿越区域造成资源占用&#xff08;当同一条路由来自不同区域&#xff0c;路由器会先…...

大数据新视界 --大数据大厂之 Ibis:独特架构赋能大数据分析高级抽象层

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

总结TypeScript相关知识

目录 引入认识特点安装使用变量声明类型推导 JS 和 TS 共有类型number类型boolean类型string类型Array类型null和undefined类型object类型symbol类型对象类型函数类型 可选和只读type 和 interface索引签名类型断言非空类型断言类型缩小严格赋值检测现象TS 新增类型字面量类型a…...

pdf怎么编辑修改内容?详细介绍6款pdf编辑器功能

■ pdf怎么编辑修改内容&#xff1f; PDF&#xff08;Portable Document Format&#xff09;作为一种广泛使用的文件格式&#xff0c;具有特点包括兼容性强、易于传输、文件安全性高、跨平台性、可读性强、完整性、可搜索性、安全性、可压缩性。 PDF文件本身是不可以直接进行编…...

【Blender Python】4.获取场景对象的几种方式

概述 有时候我们需要获取场景中已经添加或存在的对象。本节就总结在Blender Python中获取场景中对象的一些方法。 通过名称获取 py.data的objects()方法返回一个对象集合&#xff0c;可以使用键名或者下标形式获取具体的对象。 在默认新建的场景中&#xff0c;存在三个对象…...

鸿蒙harmonyos next flutter通信之EventChannel获取ohos系统时间

建立通道 flutter代码&#xff1a; EventChannel eventChannel EventChannel("com.xmg.eventChannel"); ohos代码&#xff1a; //定义eventChannelprivate eventChannel: EventChannel | null null//定义eventSinkprivate eventSink: EventSink | null null//建…...

Python 代码编写规范

本规范旨在为 Python 项目的代码编写提供一致性指南。它遵循 Python 社区的 PEP 8 标准&#xff0c;并结合了通用的编程最佳实践。 1. 编码风格 1.1 缩进 使用 4 个空格 作为缩进&#xff0c;不要使用制表符&#xff08;Tab&#xff09;。 def example():if True:print(&quo…...

k8s中pod的管理

一、资源管理 1.概述 说到k8s中的pod&#xff0c;即荚的意思&#xff0c;就不得不先提到k8s中的资源管理&#xff0c;k8s中可以用以下命令查看我们的资源&#xff1a; kubectl api-resources 比如我们现在需要使用k8s开启一个东西&#xff0c;那么k8s通过apiserver去对比etc…...

JavaScript中引用数据类型的浅拷贝

在JavaScript中&#xff0c;数据类型被分为“基本数据类型”和“引用数据类型”两大类。基本数据类型包括数值型、字符型、逻辑型、未定义型(undefined)、空型(null)和ES6新增的Symbol类型&#xff0c;引用数据类型包括数组、对象和函数。 当我们在程序中执行变量赋值操作的时候…...

自闭症寄宿学校陕西:提供综合发展的教育环境

在陕西这片古老而充满希望的土地上&#xff0c;有一所特殊的学校——星贝育园康复中心&#xff0c;它如同一座灯塔&#xff0c;照亮了无数自闭症儿童及其家庭前行的道路。这所全国规模较大的广泛性发育障碍全托寄宿制儿童康复训练机构&#xff0c;不仅以其专业的康复训练和独特…...

JS模块化工具requirejs详解

文章目录 JS模块化工具requirejs详解一、引言二、RequireJS 简介1、什么是 RequireJS2、RequireJS 的优势 三、RequireJS 的使用1、配置 RequireJS1.1、基础配置 2、定义模块3、加载模块 四、总结 JS模块化工具requirejs详解 一、引言 随着前端技术的快速发展&#xff0c;Jav…...

JavaScript中的异步编程:从回调到Promise

在JavaScript中&#xff0c;异步编程是一项至关重要的技能&#xff0c;它允许我们在不阻塞主线程的情况下执行耗时操作&#xff0c;如网络请求、文件读取或定时任务。随着JavaScript的发展&#xff0c;异步编程的模式也在不断演进&#xff0c;从最初的回调函数&#xff0c;到现…...

windows下DockerDesktop命令行方式指定目录安装

windows下DockerDesktop指定目录安装(重新安装) 因为DcokerDesktop占用内存较大, 并且拉去镜像后占用本地空间较多,所以建议安装时就更改默认安装路径和镜像存储路径 这里,展示了从下载到安装的过程: 首先下载DcokerDesktop;找到Docker Desktop Installer.exe 并重命名为 do…...

排查和解决JVM OOM实战

JVM OOM介绍 Java内存区域布局 下面的分析中都是基于JDK 8开始的。关于JMM不过多介绍每个区域的作用。OOM不单只会发生在堆内存&#xff0c;也可能是因为元空间或直接内存泄漏导致OOM&#xff0c;此时在OOM的详细信息中会有不同体现。 Java OOM的类别 java.lang.OutOfMemory…...

【Swift官方文档】7.Swift集合类型

集合类型 使用数组、集合和字典来组织数据。Swift 提供了三种主要的集合类型&#xff1a;数组、集合和字典&#xff0c;用于存储值的集合。数组是有序的值集合。集合是无序的唯一值集合。字典是无序的键值对集合。 Swift 中的数组、集合和字典始终清晰地指明它们可以存储的值…...

QT调用最新的libusb库

一&#xff1a;下载libusb文件 下载最新的库的下载网站&#xff1a;https://libusb.info/ 下载&#xff1a; 解压后目录如下&#xff1a; 二&#xff1a;库文件添加QT中 根据自己的编译器选择库&#xff1a; ①将头文件中添加libusb.h ②源文件中添加libusb-1.0.lib ③添加…...

白嫖EarMaster Pro 7简体中文破解版下载永久激活

EarMaster Pro 7 简体中文破解版功能介绍 俗话说得好&#xff0c;想要成为音乐家&#xff0c;就必须先拥有音乐家的耳朵&#xff0c;相信很多小伙伴都已经具备了一定的音乐素养&#xff0c;或者是说想要进一步得到提升。那我们就必须练好听耳的能力&#xff0c;并且把这种能力…...

使用JavaScript写一个网页端的四则运算器

目录 style(内联样式表部分) body部分 html script 总的代码 网页演示 style(内联样式表部分) <style>body {font-family: Arial, sans-serif;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f0f0f0;}.calculator {…...

Linux find命令详解及实用示例

Linux 系统中的 find 命令是一个功能强大的工具&#xff0c;用于在文件系统中搜索文件并执行相应的操作。无论是系统管理员还是普通用户&#xff0c;掌握 find 命令都能极大地提高工作效率。本文将详细介绍 find 命令的用法&#xff0c;并通过多个示例展示其在实际中的应用。 …...

CSS基础-常见属性(二)

6、CSS三大特性 6.1 层叠性 如果样式发生冲突&#xff0c;则按照优先级进行覆盖。 6.2 继承性 元素自动继承其父元素、祖先元素所设置的某些元素&#xff0c;优先继承较近的元素。 6.3 优先级 6.3.1 简单分级 1、内联样式2、ID选择器3、类选择器/属性选择器4、标签名选择器/…...

Spring Boot 2.4.3 + Java 8 升级为 Java 21 + Spring Boot 3.2.0

简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 Spring Boot 2.4.3 + Java 8 升级为 Java 21 + Spring Boot 3.2.0前言更换 Java 21 SD…...

如何利用免费音频剪辑软件制作出精彩音频

现在有许多免费的音频剪辑软件可供选择&#xff0c;它们为广大用户提供了丰富的功能和便捷的操作体验&#xff0c;让音频编辑变得更加轻松和有趣。接下来&#xff0c;让我们一起走进这些免费音频剪辑软件的世界&#xff0c;探索它们的独特魅力和强大功能。 1.福昕音频剪辑 链…...

安宝特分享 | AR技术重塑工业:数字孪生与沉浸式培训的创新应用

在数字化转型的浪潮中&#xff0c;AR&#xff08;增强现实&#xff09;技术与工业的结合正在呈现新的趋势和应用延伸。特别是“数字孪生”概念的崛起&#xff0c;为AR技术在工业中提供了独特而创新的切入点。 本文将探索AR如何与数字孪生、沉浸式体验和实用案例相结合&#xf…...

专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结

目录 搜索 vs 深度优先遍历 vs 深度优先搜索 vs 宽度优先遍历 vs 宽度优先搜索 vs 暴搜 1.深度优先遍历 vs 深度优先搜索(dfs) 2.宽度优先遍历 vs 宽度优先搜索(bfs) 2.关系图暴力枚举一遍所有的情况 3.拓展搜索问题全排列 决策树 1. 计算布尔⼆叉树的值&#xff08;medi…...