【Linux修行路】信号的产生

目录

⛳️推荐

一、信号的产生

二、产生信号的系统调用

2.1 kill——给指定的进程发送指定的信号

2.2 模拟实现指令 kill

2.3 raise——给调用的进程发送指定的信号

2.4 abort——给调用者发送 6 号信号

三、验证哪些信号不可以被捕捉

四、为什么除0和解引用空指针会给进程发信号呢?

五、alarm——设置闹钟


⛳️推荐

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站【Linux修行路】动静态库详解点击跳转到网站

一、信号的产生

  • 键盘组合键ctrl+c 给进程发送2号信号;ctrl+\ 给进程发送3号信号;ctrl+z 给进程发送19号信号(该信号无法被 signal 信号捕捉)。

  • 指令kill -signo pid

  • 系统调用killraiseabort

  • (硬件)异常:例如常见的除0(Floating point exception),当程序中出现除0异常,操作系统就会给对应的进程发送 8 号信号,来终止进程(这是 8 号信号的默认动作);对空指针解引用(Segmentation fault),当程序中出现对空指针解引用的时候,操作系统会给对应的进程发送 11 号信号。

  • 软件条件:管道通信中,写端正常,读端关闭,操作系统会给写端进程发送 13 号信号,终止掉正在进行向管道中写入的进程。alarm 闹钟 。

无论信号是如何产生的,最终一定是由操作系统发送给进程的,因为操作系统是进程的管理者。

二、产生信号的系统调用

2.1 kill——给指定的进程发送指定的信号

image-20240308092323511

2.2 模拟实现指令 kill

#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <string>using namespace std;void Manual(char *directives)
{cout << "\n\t" << directives << " signum pid\n\n";
}int main(int argc, char *argv[])
{if(argc != 3){Manual(argv[0]);exit(1);}int signum = stoi(argv[1]);int pid = std::stoi(string(argv[2]));cout << signum << ' ' << pid <<endl;pid_t ret = kill(pid, signum);if(ret == -1){perror("kill");exit(1);}return 0;
}

2.3 raise——给调用的进程发送指定的信号

image-20240308102100461

raise 就相当于:kill(getpid(), signum)

2.4 abort——给调用者发送 6 号信号

image-20240308102625369

abort 函数内部,不仅会执行自定义捕捉(前提是捕捉了 6 号信号),在执行完自定义捕捉之后,还要去执行 6 号信号默认的终止动作。通过 kill 指令去给进程发送 6 号信号,进程只会执行捕捉动作(前提是对 6 号进行了捕捉)或者只会执行默认动作(前提是没有对 6 号信号做捕捉)。

三、验证哪些信号不可以被捕捉

#include <iostream>
#include <signal.h>
#include <unistd.h>using namespace std;void myhandler(int signo)
{cout << "process get a signal: " << signo << endl;// exit(1);
}int main()
{// signal(2, myhandler);signal(19, myhandler);for(int i = 1; i <= 31; i++){signal(i, myhandler);}while(true){cout << "Hello Linux" << ' ' << getpid() << endl;sleep(1);}return 0;
}

先通过循环将31个信号都捕捉,然后在命令行通过 kill 给进程发送信号,看是否被成功捕捉。经过验证 9、19 号信号都无法被捕捉。其中 9 号信号是杀进程,19 号信号是暂停进程。

四、为什么除0和解引用空指针会给进程发信号呢?

以除0为例,首先,程序中所有的指令是需要被 CPU 来执行的,计算任务也不例外。所以 CPU 里面有特定的寄存器来存储操作数,还有一个状态寄存器,里面都是比特位级别的标记位,其中有一个标记位就是用来表示当前运算是否发生溢出,当 CPU 在执行除 0 的时候,会发生溢出,此时 CPU 就会去修改溢出标记位,这些寄存器中的内容,都属于当前进程的上下文数据,当进程切换的时候,这些数据同时也会被其它进程的上下文数据替换,当该进程再一次被替换进 CPU 执行的时候,这些上下文数据又会恢复出来。**所以任何异常只会影响该进程本身,并不会波及到操作系统。**CPU 是也是硬件资源,操作系统作为硬件的管理者,它是必须要关心硬件的健康,所以当 CPU 中的溢出标志位被设置成溢出的时候,操作系统一定是能知道的,(本质上,发生溢出会给操作系统发送中断),操作系统知道后就会向该进程发送对应的信号。

空指针解引用、越界访问等本质都是因为虚拟到物理转化失败,转化失败还导致硬件报错,最终被操作系统识别到。

程序对于异常信号,默认动作是让程序立即终止。但是我们可以在程序中对异常信号进行捕捉,如果捕捉方法里没有做特殊处理,比如说让程序退出,那这导致的后果就是程序不会立即终止,而是一直被调用运行,硬件错误就一直存在,操作系统就会一直给进程发送异常信号

总结:程序中出现的所有异常,最终一定会转化成硬件错误,操作系统能够识别这种硬件错误,最终给进程发送对应的信号。

image-20240308133955080

信号捕捉并不是为了让我们来解决问题的,而是当收到这个信号后,程序可能要被立即终止,信号捕捉给了我们应对程序即将被终止的机会,我们可以在捕捉函数里做一些数据保存,打印日志等工作。

五、alarm——设置闹钟

image-20240308135828669

  • seconds:闹钟将在 seconds 秒时候响起(给进程发送 14 号信号),如果 seconds == 0 ,则之前设置的闹钟会被取消,并将剩下的时间返回。

  • 返回值:返回之前闹钟的剩余秒数,如果之前未设闹钟,或者上一次设置的闹钟已经响过了,那么返回的就是 0 。

小Tips:如果在上一次闹钟还没响的时候,再一次调用 alarm 函数设置闹钟,那么这一次调用的返回值就是上一次闹钟的剩余时间,并且闹钟的响应时间会被更新成这一次的,上一次那个还没响的闹钟就会被作废。

设置闹钟

#include <iostream>
#include <unistd.h>using namespace std;int main()
{int n = alarm(5);while(true){cout << "process is running..." << endl;sleep(1);}return 0;
}

image-20240308141730584

捕捉闹钟信号

#include <iostream>
#include <signal.h>
#include <unistd.h>using namespace std;void handler(int signum)
{cout << "get a signal: " << signum << endl;
}int main()
{signal(14, handler);int n = alarm(5);while(true){cout << "process is running..." << endl;sleep(1);}return 0;
}

image-20240308142040976

alarm 返回值验证

#include <iostream>
#include <signal.h>
#include <unistd.h>using namespace std;void handler(int signum)
{cout << "get a signal: " << signum << endl;int n = alarm(5); // 闹钟每五秒响一次cout << n << endl;
}int main()
{signal(14, handler);int n = alarm(50);while(true){cout << "process " << getpid() << " is running..." << endl;sleep(1);}return 0;
}

第一次设置的闹钟是 50 秒,在前 50 秒内,通过命令行向进程发送 14 号信号,此时程序就会去执行 handler 方法,在该方法中又调用了一个 alarm,这就是前一个闹钟还没响,就又设置了一个闹钟。

在这里插入图片描述

🎁结语:

        今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,您的支持就是我前进的动力!

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

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

相关文章

【C++】——vector

文章目录 vector介绍vector的使用vector的构造vector迭代器vector空间增减vector增删查改 vector介绍 vector是一个动态数组&#xff0c;可以根据需求变大变小vector支持随机访问vector会自动管理内存分配和释放vector在尾部添加和删除的效率非常高&#xff0c;中间和头部插入较…

Leetcode面试经典150题-134.加油站

解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {public int canCompleteCircuit(int[] gas, int[] cost) {/**如果只有一个加油站&#xff0c;那它本来就在那个为止&#xff0c;0就是它的编号?但是这只是你的想象&#xff0c;题目有个变态规定&#xff0c;自…

GD32/STM32启动过程

GD32/STM32启动过程 文章目录 GD32/STM32启动过程前言一、系统架构二、自举配置三、启动文件四、启动流程总结 前言 本文以STM32F407为例简单介绍其启动过程。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、系统架构 STM32F407的系统架构如图所…

DRW的公式推导及代码解析

流程 分阶段指定β值 # 根据当前epoch计算使用的beta值idx epoch // 160 # 每160轮epoch切换一次加权系数betas [0, 0.9999] # 两个beta值beta betas[idx] # 根据idx选择beta值 计算有效样本的权重 对权重进行归一化 &#xff08;每类权重值 / 权重总和&#xff09;* …

k8s--pod控制器--1

Pod控制器介绍 Pod是kubernetes的最小管理单元&#xff0c;在kubernetes中&#xff0c;按照pod的创建方式可以将其分为两类&#xff1a; 自主式pod&#xff1a;kubernetes直接创建出来的Pod&#xff0c;这种pod删除后就没有了&#xff0c;也不会重建 控制器创建的pod&#xf…

OpenStack × OceanBase: 打造高可用可扩展的基础设施平台

OceanBase 社区资深总监封仲淹在9月3日参加 OpenInfra 亚洲峰会中&#xff0c;分享了OceanBase与OpenStack的联合解决方案。本文将介绍这一联合方案的技术亮点及其为用户带来的独特价值。 OpenStack长期以来一直是云计算领域的先行者&#xff0c;通过提供强大的开源平台&#x…

前端正确设置资源上下文路径ContextPath(发布目录outDir 、公共基础路径),保证打包部署后站点能正常加载资源。

文章目录 引言I 处理资源上下文路径ContextPathjavascript对象获取上下文路径使用`./` 加载资源文件Vite 的basepublicPath是webpack部署应用包时的基本 URLII 知识扩展:URL的识别2.1 标准的链接格式2.2 URL中的?涵义2.3 URL中的&涵义2.4 传参III #fragment3.1为网页位置…

圆锥曲线练习

设 A ( x 1 , y 1 ) , B ( x 2 , y 2 ) A\left( x_{1}, y_{1} \right), B\left( x_{2}, y_{2} \right) A(x1​,y1​),B(x2​,y2​) l : y k ( x 2 ) l: y k\left( x2 \right) l:yk(x2) 显然 y 0 y0 y0符合题意 当 k ≠ 0 k\neq 0 k0 联立 l l l和 C C C ( k 2 1 2 ) x…

shader 案例学习笔记之偏移

效果 代码 #ifdef GL_ES precision mediump float; #endifuniform vec2 u_resolution; uniform float u_time;vec2 brickTile(vec2 _st, float _zoom){_st * 5.;_st.x step(1., mod(_st.y,2.0)) * 0.5;return fract(_st); }float box(vec2 _st, vec2 _size){_size vec2(0.5)…

【软考中级攻略站】-软件设计师(5)- 软件工程

软件生存周期 什么是软件生存周期&#xff1f; 软件生存周期指的是一个软件从开始构思到最终停止使用&#xff08;或被替换&#xff09;的整个过程。就像人的生命一样&#xff0c;软件也有一个从出生到死亡的过程。 软件生存周期的几个阶段 软件生存周期通常可以分为以下几…

DAY13信息打点-Web 应用源码泄漏开源闭源指纹识别GITSVNDS备份

#知识点 0、Web架构资产-平台指纹识别 1、开源-CMS指纹识别源码获取方式 2、闭源-习惯&配置&特性等获取方式 3、闭源-托管资产平台资源搜索监控 演示案例&#xff1a; ➢后端-开源-指纹识别-源码下载 ➢后端-闭源-配置不当-源码泄漏 ➢后端-方向-资源码云-源码泄漏 …

苹果宣布iOS 18正式版9月17日推送:支持27款iPhone升级

9月10日消息&#xff0c;在苹果秋季发布会结束后&#xff0c; 苹果宣布将于9月17日(下周二)推送iOS 18正式版系统。 苹果官网显示&#xff0c;iOS 18正式版将兼容第二代iPhone SE及之后的所有机型&#xff0c;加上刚发布的iPhone 16系列&#xff0c;共兼容27款iPhone。 iOS 18升…

算法学习攻略总结 : 入门至进阶,通关之路指南

❃博主首页 &#xff1a; <码到三十五> ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a; <搬的每块砖&#xff0c;皆为峰峦之基&#xff1b;公众号搜索(码到…

UE中如何制作后处理设置面板

1&#xff09;UE中如何制作后处理设置面板 2&#xff09;Magica Clothes 2插件与Burst编译问题 3&#xff09;UI大小和文本变量 4&#xff09;如何检索直线与网格的所有交点 这是第399篇UWA技术知识分享的推送&#xff0c;精选了UWA社区的热门话题&#xff0c;涵盖了UWA问答、社…

机械面试常见问题

文章目录 1.机械设计的一般思路&#xff08;方法&#xff09;2.公差等级有多少种3.机械传动的方式有哪些&#xff1f;选择的时候要考虑哪些问题&#xff1f;1. 齿轮传动2. 带传动3. 链传动4. 摩擦传动5. 螺旋传动6. 液压传动7. 气压传动8. 电磁传动总结 4.什么是宽禁带半导体&a…

4.1 符号定义伪指令

&#x1f393; 微机原理考点专栏&#xff08;通篇免费&#xff09; 欢迎来到我的微机原理专栏&#xff01;我将帮助你在最短时间内掌握微机原理的核心内容&#xff0c;为你的考研或期末考试保驾护航。 为什么选择我的视频&#xff1f; 全程考点讲解&#xff1a;每一节视频都…

【小沐学OpenGL】Ubuntu环境下glew的安装和使用

文章目录 1、简介1.1 OpenGL简介1.2 glew简介 2、安装glew2.1 命令安装glew2.2 直接代码安装glew2.3 cmake代码安装glew 3、测试glew3.1 测试glewfreeglut3.2 测试glewglfw 结语 1、简介 1.1 OpenGL简介 Linux 系统中的 OpenGL 是一个跨语言、跨平台的应用程序编程接口&#…

【C++】STL容器-string的遍历

1.引言 C STL&#xff08;Standard Template Library&#xff09;作为C标准库的核心部分&#xff0c;其重要性不言而喻。它提供了一系列高效、灵活且可复用的数据结构和算法&#xff0c;极大地提升了开发效率&#xff0c;并使得代码更加易于阅读和维护。 在STL中&#xff0c;…

根据NVeloDocx Word模板引擎生成Word(四)

前面介绍了《E6低代码开发平台》的Word模版引擎NVeloDocx&#xff0c;实现了表单的基本字段、子表、单张图片、二维码、条形码怎么基于NVelocity脚本输出到Word文件&#xff0c;都是些比较简单且常用的需求。 本篇介绍怎么基于NVeloDocx在Word中插入图表&#xff0c;目前只支持…

模型训练如何实现自动化输出评估报告、模型、特种平台

模型训练如何实现自动化 1、目标 把对文本分类【体育,教育,娱乐,经济,文学,政治】的模型实现自动化训练。 分类器:贝叶斯、支持向量机、梯度提升、随机森林、逻辑斯蒂回归 通过预设的准确率期望值与训练轮数,获取最优的分类器模型,当模型评估的准确率大于期望值时即…