【Linux】进程信号及信号产生

news2024/11/14 19:38:48

文章目录

  • 一. 生活层面的信号
  • 二. 进程信号
  • 三. 硬件中断
  • 四. 信号产生
  • 五. Term&Core
    • 1. 核心转储的意义
    • 2. 云服务器为什么关闭核心转储
    • 3. core dump标志
  • 六. 总结
  • 结束语

在这里插入图片描述

一. 生活层面的信号

在学习进程信号前,我们不妨认识一下现实中有哪些信号。
日常生活中,眼神,语气,手势,等等,都可以是一个信号,都可以传递一定信息。而我们常见的红绿灯,红灯代表禁止通行,绿色代表允许通行,黄灯代表转换过渡。这些并不是我们一开始就知道,是因为大众的共识性。而各种手势,也是在幼儿园老师有所教导,我们才得以认知。
所以信号的创建是需要被人们所认知的。

我们可以通过生活中的一些事情引出信号的预备知识
进程信号的预备知识

网购是当今热门的购物选择,当我们网购的东西送到时,我们就会收到,“快递到了”这一信号,
首先,这一信号是大众的共识性认知,我们可以“识别信号
其次,在收到这一信号时,我们可能立刻就去取快递了,但是也有可能我们正在做着一些不方便离开的事情,所以我们不会立刻去取快递。这就说明,信号的处理和信号的接收并不一定衔接。我们可以在“合适的时候处理信号
并且,如果我们不立刻去取快递,我们还需要记录“快递到了”这一信号,因为我们需要之后处理。我们需要“记住有一个信号要处理
最后,对于快递的处理,1. 默认动作(打开快递);2. 自定义动作(如果是卖给女朋友的礼物,就送给女朋友);3. 忽略
PS:快递的到来是不定时的,接收快递和我们已经在做的事是异步的

总结一下:

  1. 信号创建首先是需要能被人们识别
  2. 接收信号后可以不立刻处理信号,等到合适的时候再处理
  3. 因为可以不立刻处理信号,那么就需要存在记录信号的能力
  4. 信号的产生对于进程来说是异步

二. 进程信号

我们可以通过kill -l命令查看所有的进程信号
在这里插入图片描述
其中,1到31是非实时信号34到64是实时信号
本篇博客仅学习部分非实时信号。
实时信号,只需要保存有无产生,不需要立刻处理,具体处理可以之后进行。
操作系统可被分为实时系统非实时系统Linux和Windows都是非实时系统,而实时系统是高响应的,需要对任何命名立刻响应。比如车载系统中的刹车

而非实时信号刚好有32个,操作系统使用位图来存储非实时信号。存储在进程的pcb结构体中,所以发送信号其实是将信号写入进程pcb的位图,修改位图的比特位,将0->1
比特位的位置:信号的编号
比特位的内容:是否收到该信号

在Linux中,当我们不小心写了一个死循环的程序,我们可以通过ctrl+c终止这个程序
在这里插入图片描述
ctrl+c其实就是通过键盘输入给OS,OS捕捉,然后发送一个信号给当前进程,然后终止这个程序。
另外还有一点需要注意,ctrl+c只能终止前台进程,如果我们将程序变为后台运行,则无法通过ctrl+c终止,不过可以使用kill+信号终止进程
在这里插入图片描述

其实ctrl+c本质是让OS给指定进程发送2号信号SIGINT

接下来我们通过singal()函数验证一下
在这里插入图片描述

signal函数可以接收信号,并由我们指定接收该信号后,执行的动作。
比如ctrl+c是发送了2号信号,执行动作是终止程序
int signum:接收的信号
sighandler_t handler:sighandler是一个函数指针,函数的返回值是void,参数是int。

接下来,我们用一个程序证明ctrl+c本质是发送了2号信号
在这里插入图片描述

可以看到,这次我们使用ctrl+c没能终止程序,而且打印出了"get signal:2",并且当我们发送2号信号,也是执行handler方法
首先,我们使用signal函数对2号信号进行捕捉,并且让handler作为2号信号的处理动作
并且OS会将接收的信号传参给handler。所以我们使用ctrl+c没能终止程序,而是打印出了handler的内存
我们上面也讲了,对信号的处理分三种:默认动作,自定义动作,忽略
终止程序就是2号信号的默认动作,而我们编写的handler就是自定义动作


我们可以通过man 7 signal查看信号的默认动作
在这里插入图片描述
Term就代表终止进程
PS:ctrl+\是发送3号信号SIGQUIT,但是9号信号SIGKILL是管理员信号,即使使用signal捕捉执行自定义动作,kill -9还是执行默认动作即终止进程。

三. 硬件中断

我们按下crtl+c,那计算机是怎么知道我们输入了什么数据呢?
键盘其实是通过硬件中断的方式,通知操作系统,我们按下了按键
注意:硬件中断只是让操作系统知道我们按下了按键,但是具体按了什么,操作系统此时还不知道

那么,什么是硬件中断呢?
在这里插入图片描述

内核中有中断控制器这样一个硬件,我们拿8259举例,当我们按下键盘,其实是发送了电脉冲,然后通过中断控制器发送给特定的CPU特定的针脚。当针脚处于高电频时,就相当于写入数据,CPU中的寄存器会写入高电频针脚的编号。这就是发送中断的过程
中断向量表类似于函数指针数组,CPU获得中断后,就会找中断向量表中对应的函数指针调用对应的方式
比如9号针脚高电频,那么寄存器中就会写入9,然后找中断向量表中9号函数指针,调用“从键盘获取对应数据”的方法。这就是硬件中断。

注意:键盘被按下,键盘哪些被按下是两个不同的步骤。

键盘被按下,对应的是硬件中断
键盘哪些被按下,对应的是中断向量表中的方法获取键盘输入的数据。

所以ctrl+c发生信号的本质是:

先按下按键,CPU获得硬件中断,然后调用方法,OS去读取键盘输入的ctrl+c数据,OS再将其解释为信号,并发送给前台进程,写入其pcb结构体的信号的位图

四. 信号产生

信号的第一种产生方式是通过键盘ctrl+cctrl+/
第二种产生方式是kill指令

第三种产生方式是通过系统调用

第一个系统调用函数是kill()
在这里插入图片描述

int pid:指定给某个进程发送信号
int sig:发送几号信号

接下来,我们可以模拟实现kill命令

mykill.cc
模拟实现 kill 命令

#include<iostream>
#include<cstdlib>
#include<cerrno>
#include<cstring>
#include<unistd.h>
#include<signal.h>
#include<string>
#include<sys/types.h>


using namespace std;

//传参不正确,展示使用手册
void Usage(string proc)
{
    cout<<"Usage:"<<endl;
    cout<<"\t"<<proc<<" 信号编号 目标进程"<<endl;
}

//   ./mykill 9 1234
int main(int argc,char*argv[])
{
    //argc:命令行参数个数
    if(argc!=3)
    {
        //第一个参数是 比如: ./进程名
        Usage(argv[0]);
        exit(1);  
    }
    
    //信号
    int signo=atoi(argv[1]);
    //目标进程的pid
    int target_id=atoi(argv[2]);

    //发送信号
    int n=kill(target_id,signo);
    if(n!=0)
    {
        cerr<<errno<<" : "<<strerror(errno)<<endl;
        exit(2);
    }

    return 0;
}

myproc.cc
死循环程序,需要被杀死的程序

#include<iostream>
#include<unistd.h>

using namespace std;

int main()
{
    while(1)
    {
        cout<<"我是一个进程,我正在执行...,我的pid:"<<getpid()<<endl;
        sleep(1);
    }


    return 0;
}

运行结果如下:
在这里插入图片描述


第二个系统调用函数是raise()
在这里插入图片描述

int sig:几号信号

在这里插入图片描述
可以看到,调用完raise(2)后,程序就结束了,并没有输出后续内容。


第三个系统调用函数是abort()
在这里插入图片描述
调用abort()函数,会给当前进程发送6号信号SIGABRT
但是abort()是C语言的接口,其函数内部还有类似exit的操作,所以即使使用signal函数捕捉6号信号,进行自定义动作,abort函数还是会使进程终止


第四种信号产生的方式是由软件条件产生信号
在这里插入图片描述

unsigned int seconds:seconds秒之后给该进程发送14号信号SIGALRM
但是我们可以通过发送14号信号,提前触发alarm。而当我们再调用alarm(),其返回值就是上一次alarm还剩余的时间
但如果我们提前触发alarm,但是没有重新设置,则之后还会再收到一次alarm。alarm(0)代表取消闹钟
比如我们设置一个alarm(30),但如果我在20秒时,给该进程发送14号信号,然后我再调用alarm(15),那么就会再设置一个15秒的闹钟,但是这个闹钟的返回值是上一次闹钟剩余时间,也就是10秒。
PS:alarm是系统接口,OS中有维护alarm的结构体,会定期查看是否有闹钟超时


第五种信号产生的方式是硬件异常

我们在编写C/C++代码时,有时候可能会出现除0野指针的情况
他们的报错分别是这样的
在这里插入图片描述
我们以前在语言层面的理解,就是程序崩溃了。
但是在操作系统层面,其实是OS给进程发送信号,终止进程。


除0引发的硬件异常
在这里插入图片描述

CPU中其实有很多寄存器,计算就发生在寄存器中。而有一个寄存器叫作状态寄存器,当本次计算溢出时,状态寄存器就会被置为1反之为0
而一旦状态寄存器为1,就会发生硬件异常,操作系统会得知这个异常。CPU还会存储当前调度的进程的pcb结构体的地址,操作系统在得知异常后,根据CPU记录的pcb地址,给该进程发送信号

除0本质是触发了硬件异常,操作系统给该进程发送了8号信号
在这里插入图片描述


野指针引发的硬件异常

在这里插入图片描述

如果我们对空指针解引用,修改其内部的值。
空指针默认是虚拟地址的0地址,而通过页表映射到物理地址
修改指针内部的值,第一步是先进行虚拟地址到物理地址的转换
而页表其实是有MMU硬件——内存管理单元进行管理的
PS:MMU硬件是CPU的其中一个硬件
当出现以下情况之一,MMU就会报错,触发硬件异常

  1. 虚拟地址没有映射,MMU硬件报错
  2. 有映射,但是没有修改的权限,MMU硬件报错

而MMU硬件报错,触发硬件异常,OS根据CPU中记录的当前进程的pcb地址,并发送信号,终止该进程。

野指针本质也是触发了硬件异常,操作系统给该进程发送了11号信号
在这里插入图片描述


五. Term&Core

在这里插入图片描述
我们之前讲了,Term是终止进程的意思,但是刚刚的除0,野指针的8号,13号信号时Core,但好像也是直接终止进程,那么这两个有什么差别吗?


首先,OS可以将一个进程在异常的时候,可以将核心代码部分进行核心转储,将内存中进程的相关数据,全部转储到磁盘中。并在可执行程序的目录下,形成core.pid的核心转储文件。

我们可以通过ulimit -a指令查看当前进程的限制
在这里插入图片描述
而为什么我们之前没有看到核心转储文件呢,因为云服务器默认是关闭形成核心转储文件这一功能的,将可形成的核心转储文件大小设为0。

我们可以使用ulimit -c 大小 设置可形成的核心转储文件大小
在这里插入图片描述
而这时,我们就可以发现Term和Core二者的差别了。

在这里插入图片描述
在这里插入图片描述

我们发现,Action显示是Core的信号,在终止进程后,会显示出(core dumped),并在当前目录下形成了core文件

所以,Term的终止就是终止,没有多余动作
Core则是在终止时,会先进行核心转储,再终止进程


1. 核心转储的意义

在这里插入图片描述
我们打开core文件,发现其实一个二进制文件。不是给我们看的
那核心转储的意义是什么呢?

其实,信号和退出码的作用是一样的,都是在进程结束后,反馈给程序员的信息,当程序异常结束时,我们可以知道是正常结束,还是异常终止;异常终止又是因为什么?
而core文件其实就是给程序员后期调试用的文件。
我们需要使用Debug方式形成可执行程序,并且使用gdb调试,才可以体会core文件的意义。(gcc / g++默认是形成release版本,最后加-g选项形成Debug版本)

在这里插入图片描述
通过core文件,我们在gdb的调试中,可以直接定位到产生异常的位置。
这种调试称为事后调试

2. 云服务器为什么关闭核心转储

一个大的程序,出现问题时,都无法立刻解决,程序可能会崩溃,但可能会有检测程序对其重启,而如果核心转储处于打开状态,一次崩溃就会形成一个core文件;如果这个程序在半夜崩溃,就会一直重启,崩溃,反复进行,每一次重启的进程又不同,正如上述,同一个程序,只是变成进程后的pid不同,Core终止就会重新形成一个core文件
这样就会造成很多浪费,所以云服务器一般关闭核心转储功能。
ulimit -c 0就是关闭核心转储

3. core dump标志

在进程等待时,父进程获取子进程的退出信息使用的status位图结构
在这里插入图片描述
在正常终止时,位图的8~15位是退出码
被信号所杀时,0~6是终止信号,而第8位是core dump标志。
如果该进程核心转储功能是打开的,那么该进程的core dump为1,反之为0。

六. 总结

  1. 所有的信号产生,最终都要OS来执行,因为OS是软硬件的管理者,也是进程的管理者
  2. 信号的处理可以不立刻处理,进程可以在合适的时候再对信号进行处理
  3. 如果不立即处理,那么信号需要被记录到pcb结构体
  4. 一个进程在没有收到信号的时候,是知道如何处理某个信号的,因为在编码时已经提供给每个进程了
  5. 任何一种信号产生,不管是通过键盘,还是指令,系统调用…本质都是操作系统往进程的pcb结构体中写入信号

结束语

本篇内容到此就结束了,感谢你的阅读!

如果有补充或者纠正的地方,欢迎评论区补充,纠错。如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

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

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

相关文章

净利润下滑13%,帅丰电器已掉队?

近年来&#xff0c;随着市场竞争加剧&#xff0c;厨电行业加速洗牌&#xff0c;超60%杂牌或被淘汰出局&#xff0c;三类品牌全部被清退。而作为毛利最高的厨电细分市场&#xff0c;集成灶行业吸引了大批企业涌入&#xff0c;市场渗透率快速提升&#xff0c;已经超过30%&#xf…

如何入门数据分析

如何入门数据分析&#xff1f; 随着数字经济、大数据时代的发展&#xff0c;数据已然成为当下时代最重要的盈利资源&#xff0c;让企业在做决策和计划方案时更有针对性和依据&#xff0c;能提前预测市场发展方向&#xff0c;做好布局。由此而产生的数据分析岗位也逐渐被更多企业…

亚马逊、Lazada、阿里国际、eBay、Temu、Ozon好消息不断,机会来了

1. 亚马逊第一季度营收1273.58亿美元 同比扭亏为盈 亚马逊2023财年第一季度财报。亚马逊第一季度净销售额为1273.58亿美元&#xff0c;与上年同期的1164.44亿美元相比增长9%&#xff0c;不计入汇率变动的影响为同比增长11%&#xff1b;净利润为31.72亿美元&#xff0c;上年同期…

“智慧交通”转型升级+创新发展策略

随着“互联网交通”的应用创新推陈出新&#xff0c;传统轨道交通行业客户服务中心已难以满足乘客对便捷高效的客户服务需求&#xff1b;节假日人流量激增&#xff0c;客户服务人手不足&#xff0c;交通、站点堵塞、信息更新不及时等问题是常态。因此&#xff0c;“智慧城市”交…

多租户SAAS系统涉及实战解决方案—案例JeecgBoot低代码平台

JeecgBoot免费低代码平台&#xff0c;提供一键切换多租户模式机制&#xff01;快速实现全系统的saas租户方案&#xff0c;通过租户ID进行数据隔离。 租户设计思路 1、开启全系统租户隔离 开启方法 将 org.jeecg.config.mybatis.MybatisPlusSaasConfig#OPEN_SYSTEM_TENANT_CO…

为什么是三次握手和四次挥手

文章目录 为什么是三次握手为什么是四次挥手什么是TIME_WAIT状态解决TIME_WAIT状态引起的bind失败的方法 为什么是三次握手 因为这是双方都有收发的最小次数 握手的目的&#xff1a;确认网络好着没&#xff0c;对方好着没 确认双方主机是否健康&#xff08;双方&#xff09;…

美国访问学者访问J1签证和商务B1签证的区别

美国校方通常希望他国的访问学者申请访问类签证&#xff08;J1&#xff09;&#xff0c;当然也有很少一部分人以商务签证&#xff08;B1&#xff09;的身份入境&#xff0c;知识人网小编就这两种签证的区别做一下简单介绍。 交流访问学者签证&#xff08;J1&#xff09;旨在促进…

UG NX二次开发(C++)-建模-利用UF_CURVE_ask_line_data()获取直线的矢量

文章目录 1、前言2、总体思路3、代码实现3.1 在视图区选择对象3.2 将选择对象转换为直线对象3.3创建获取直线矢量的函数 4、测试效果 1、前言 选择一条直线&#xff0c;获取直线的矢量方向&#xff0c;采用的是获取直线的数据&#xff0c;并根据直线的首末端点计算矢量方向&am…

【TCP/IP 网络模型】

TCP/IP 网络模型 OSI七层模型、TIP/IP四层模型 OSI七层模型 应用层&#xff0c;负责给应用程序提供统一的接口&#xff1b; 表示层&#xff0c;负责把数据转换成兼容另一个系统能识别的格式&#xff1b; 会话层&#xff0c;负责建立、管理和终止表示层实体之间的通信会话&…

Java基础(十五)集合框架

1. 集合框架概述 1.1 生活中的容器 1.2 数组的特点与弊端 一方面&#xff0c;面向对象语言对事物的体现都是以对象的形式&#xff0c;为了方便对多个对象的操作&#xff0c;就要对对象进行存储。另一方面&#xff0c;使用数组存储对象方面具有一些弊端&#xff0c;而Java 集合…

研报精选230504

目录 【行业230504国联证券】食饮农业2022年报与1Q23季报总结&#xff1a;食饮业绩稳步改善&#xff0c;农业低猪价推动去产能 【行业230504中邮证券】美护行业22年&23Q1财报总结&#xff1a;龙头逆境彰显韧性&#xff0c;期待Q2行业加速 【行业230504安信证券】交通运输行…

3. 内存分区模型

一、内存分区模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域 代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的全局区&#xff1a;存放全局变量和静态变量以及常量栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值&a…

AI落地:程序员如何用AI?

对于程序员来说&#xff0c;真正能提高效率、可落地的AI应用场景都有哪些&#xff1f; 目前已经能切实落地&#xff0c;融入我日常工作生活的有以下几个场景&#xff1a; 开发工作&#xff1a;自然语言生成代码&#xff0c;自动补全代码 日常工作学习&#xff1a;写作、翻译、…

通达信如何检测未来函数?

未来函数可能引用未来发生的数据&#xff0c;对原来的判断进行修改&#xff0c;这会导致信号漂移&#xff0c;比如产生原来没有的信号、原来的信号改变位置或者已经产生的信号消失。 一、未来函数如何偷梁换柱&#xff1f; 单纯讲概念&#xff0c;对未来函数也没有深刻的认识…

java中Queue、BlockingQueue以及DelayQueue的用法

java中Queue、BlockingQueue以及DelayQueue的用法 一 Queue 的用法Java中Queue的api 二 BlockingQueue 的用法阻塞队列的边界 三 DelayQueue使用DelayQueue常见的应用场景 一 Queue 的用法 Queue(队列)&#xff1a;其特性是先进先出。只允许在表的一端进行插入&#xff0c;而在…

【图像分割】视觉大模型SEEM(Segment Everything Everywhere All at Once)原理解读

文章目录 摘要&#xff08;效果&#xff09;二、前言三、相关工作四、method4.1 多用途4.2 组合性4.3 交互式。4.4 语义感知 五、实验 论文地址&#xff1a;https://arxiv.org/abs/2304.06718 测试代码&#xff1a;https://github.com/UX-Decoder/Segment-Everything-Everywher…

Flask使用Flask-SQLAlchemy对数据库操作详解一(配置、表与表之间一对一、多对一、多对多关系及增删改查参数和代码详细总结)

文章目录 1.先来一个简单的示例2.SQLAlchemy 配置&#xff08;所有的配置都在Flask初始化应用程序之前就执行了&#xff09; 3.声明模型3.1声明模型参数3.2表与表之间的关系&#xff08;详细介绍&#xff09;1.一对一关系2.多对一关系3.多对多关系 1.先来一个简单的示例 from …

【Unity3D小功能】Unity3D中实现轮船在水面上移动效果

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 标题是啥我写啥&#xff0c;大家好&#xff0c;今天给大家带来…

chatgpt帮我写的一个小程序气泡框代码

效果图 这是一个气泡框 .bubble { position: relative; padding: 10px; border-radius: 8px; background-color: #ddd; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); } .triangle { position: absolute; width: 0; height: 0; top: -10px; left: 50%; margin-left: -10px; bor…

vue集成animate.css

vue集成animate.css 一 <transition> 标签的用法二 关于animate.css三 vue集成animate.css使用 一 <transition> 标签的用法 使用<transition></transition>标签包裹要加动画的元素。 标签中添加属性name&#xff0c;表示执行动画的名字&#xff0c;不…