Linux——信号概念与信号产生方式

目录

一、概念

二、前台进程与后台进程

1.ctrl+c

2.ctrl+z

三、信号的产生方式 

1.键盘输入产生信号

2.系统调用发送信号

2.1 kill()函数

2.2 raise()函数

2.3 abort()函数

3.异常导致信号产生

3.1 除0异常

3.2 段错误异常 

4.软件条件产生信号

4.1 管道

4.2 闹钟

四、核心转储

总结


一、概念

生活中,我们也经常遇到信号,比如早八的闹钟、红绿灯、鲁大师在电脑里面抽烟、周杰伦的到底有谁知道~是几点的方向~你~才~会~收~到~暗~号~。在信号还没有产生的时候,我们已经知道什么样的信号需要如何去处理,比如早八的闹钟,在闹钟响之前,我们就知道早上要么起床去上课,要么把闹钟一关继续睡觉。

信号产生了,我们不一定要立即处理他,而是在合适的时候处理。比如你肚子疼,需要拉肚子,但是游戏已经开了,对抗路已经在操作了,今天不管,你有本事就拉裤兜,必须先把这把打完再去。因此我们要对信号进行暂时保存

同时,我们并不清楚具体什么时候肚子痛,因此信号到来相对于我现在正在打的游戏,是异步(多执行流同时进行操作)的。

小总结:

我们能识别信号,同时知道该如何处理

信号是异步的

可以对信号进行暂时保存

在合适的时候处理信号

信号是向目标进程发送消息通知的一种机制

二、前台进程与后台进程

1.ctrl+c

进程在运行时,一般都是前台进程,如下代码,./mytest运行起来,我们输入命令没用反应,但我们运行时输入ctrl+c可以终止掉进程。

如果我们执行的时候在后面加上 & ,就让进程在后台运行,此时输入命令可以反应,但是进程不能被ctrl+c终止。 

这是因为前台进程只能有一个,后台进程可以有多个,由于shell也是一个进程,因此当进程在前台运行时,shell需要退入到后台进程中去,因此无法接受指令。而你现在输入ctrl+c终止进程,就是让前台进程终止,自然进程就结束了。

而当你进程以后台方式启动时,前台进程是shell,因此输入指令可以有结果,如果你输入ctrl+c,shell自己会保护自己,无法被ctrl+c终止,后台进程并没有收到ctrl+c,因此无法终止后台进程。

之前我们提到,后台进程可以有多个,比如现在我们重定向到log1.txt与log2.txt,输入指令jobs可以看到后台进程的运行情况。

他们在后台运行,并不影响前台shell接受指令,同时ctrl+c也无法终止。

我们输入fg + number,就可以将后台进程提到前台来,输入ctrl+c就可以终止掉该进程了。

小总结:判断是前台进程还是后台进程,看shell有没有能力接受用户输入,有就是后台进程,没有就是前台进程。 

2.ctrl+z

输入ctrl+z可以暂停前台进程,但是被暂停的进程会自动放到后台,也就是我输入指令命令行能接受了。

现在我们输入 bg+number ,就可以将暂停的后台进程继续运行。

小总结:

  • ./mytest & 让进程在后台运行
  • jobs 查看后台进程
  • fg + number 将后台进程放到前台
  • ctrl+z 暂停前台进程并放到后台
  • bg + number 将暂停的后台进程继续执行    

三、信号的产生方式 

1.键盘输入产生信号

在上面,我们学习ctrl+c终止前台进程,其实ctrl+c的本质上就是信号,他是信号表中的2号信号。

我们可以通过写代码的方式来查看该现象。

signal函数:能将收到的信号做自定义处理

  • 参数1:信号num
  • 参数2:返回值为void,参数为int的函数指针

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

using namespace std;

void sighandler(int signo)
{
    cout<<"收到了"<<signo<<"号信号"<<endl;
    exit(1);
}

int main()
{
    signal(2,sighandler);
    while(1)
    {
        cout<<"pid: "<<getpid()<<endl;
        sleep(1);
    }
}

运行后发现,输入ctrl+c,会打印出内容,同时发送2号指令也会打印出相同的内容,由此可见,ctrl+c 等价于发送2号信号 。也就是键盘输入可以产生信号。

  • 我们知其然,还要知其所以然。
  • 我们在键盘中输入ctrl+c,会被操作系统接受到你的输入,因为操作系统是进程的管理者,他判断出你输入的内容是终止信号,同时是输入给当前运行的前台进程的。那么操作系统肯定需要告诉进程,信号到来了,你赶紧处理。
  • 在进程的角度来看,进程一定要通过存储来表示自己是否收到信号,收到了哪种信号。这完全可以通过位图来实现,比特位的位置代表收到的哪种信号,比特为的内容0/1代表是否收到信号。由于普通信号只有1-31个,因此用32位的整形变量就可以判断了。

  • 我们之前提到,在信号没有到来时,进程就已经知道该如何处理相关信号,因此进程还得有一张自己的函数指针数组,数组的下标与信号的编号相关,于是,当发现信号位图中有信号的到来,知道是哪一张信号,然后会调用信号相关的函数进行执行。

  • 操作系统向目标进程发送信号,其实本质上是写信号,将该进程信号位图的相关位置设置为1​

那么既然ctrl+c是一个信号,之前我们学过的ctrl+z,也应该是信号咯。当然没错,ctrl+z是20号信号SIGTSTP。还有ctrl+\,是3号信号

跟之前一样,使用signal捕获一下2号信号,3号信号,和20号信号。

9号信号不可被自定义捕捉,因为操作系统得有能力杀死任意进程,如果某个进程是恶意进程,一直在读取你的数据,或者对操作系统做破坏,那么该进程捕捉了所有信号,岂不是杀不掉了,因此操作系统设置9号信号不可被捕捉。

2.系统调用发送信号

2.1 kill()函数

有一个kill的系统调用函数,他可以往指定的进程发送指定信号。我们可以通过该函数来发送信号。

kill:给指定进程发送信号

  • 参数1:进程pid
  • 参数2:信号编号

代码如下 

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

using namespace std;


void Usage(const string& proc)
{
    cout<<"\n Usage: "<< proc <<" -signumber process"<<endl;
}

int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(0);
    }
    int signumber = stoi(argv[1]+1);
    int processpid = stoi(argv[2]);
    kill(processpid,signumber);
}

 我们就可以利用kill函数,给他传信号与进程pid,即可将信号发送给此进程。

2.2 raise()函数

kill是给任意进程发送任意信号,而raise是给自己发送任意信号

kill:给指定进程发送信号

  • 参数1:信号编号

使用很简单,如下,raise(2)代表给自己发送2号信号 

 因为我们自定义捕捉了,因此会一直收到2号信号。

2.3 abort()函数

 给自己发送abort信号,是6号信号,参数返回值都不管,直接调用即可。

我们发现,进程确实收到了6号信号,我们sighandler里面并没有让进程退出,但是进程却被Aborted终止,这是abort函数的特点,就是进程收到6号信号,你可以自定义捕捉,但捕捉完毕我仍然会终止

3.异常导致信号产生

C++我们学过异常,发生异常了,代码并不会再往后面执行,而是直接终止,除非你捕获了异常。

3.1 除0异常

如下代码,你发生了除0错误,编译的时候就会警告,当你执行的时候,告诉你浮点数异常。这是8号信号 SIGFPE。

我们将信号捕捉,运行,我们并没有写循环,按道理只会打印一次,这里发现进程在一直打印消息。

这是因为进程在运行的时候,会将进程中的数据放到CPU里面的寄存器去运行,现在CPU运算发现了除0错误,会给相应的标志位写上1,记录你的错误,操作系统就知道进程的错误了(因为操作系统是软硬件资源的管理者),那么操作系统需要发送对应信号干掉目标进程。

但是你自己的操作,将信号自定义捕捉了,杀死不了,而后进程就切换了,当进程又切换回来时,操作系统又发现你对应的标志位为1,因此又给你发送信号,从此往复,会一直发送信号,却又杀不掉你。

3.2 段错误异常 

我们写C/C++代码的时候,经常会遇到段错误。比如野指针,越阶访问等等。段错误异常是11号信号SIGSEGV,因此我们捕捉11号信号看看结果。

跟之前一样,没有写循环,依然一直报错。这是在访问虚拟内存页表时,发现页表中没有对应内容虚拟到物理的映射。发生段错误,标志位设置,操作系统发送信号给进程,进程收到信号并自定义捕捉,进程切换,又回到该进程,发现标志位为1,继续发送信号,继续套娃。

4.软件条件产生信号

4.1 管道

我们之前在学习管道的时候,当我们把读端关闭的时候,写端会直接终止,因为操作系统给写端发送SIGPIPE信号,告诉写端,兄弟别舔了,她已经把你拉黑了。此时我们并没有涉及到寄存器或者其他硬件设备,虽说有内存,但是内存空间都是我自己开辟的呀,我自己的东西我爱咋用咋用,操作系统不会无缘无故给你发信号,这就叫软件条件。

4.2 闹钟

alarm:可以设置闹钟->给当前进程发送14号信号

参数:设置几秒中后的闹钟

返回值:正常返回0,闹钟提前返回剩余时间。

在5次打印后收到了消息,返回值为0。 

综上,产生信号的方式有很多,但是发送信号只能由操作系统来完成!!!也就是向进程PCB中的信号位图写入。

四、核心转储

首先解释什么是Core Dump。当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁 盘上,文件名通常是core,这叫做Core Dump。

命令行输入指令 man 7 signal ,往下翻可以查看信号的详细信息,这里可以看到信号的动作有Term、Core、Ign(ignore)、Cont(continue)、Stop。

其他的都比较好理解,比如Ign忽略,Cont继续,Stop暂停。但是还有Term和Core这两种,我们学过的信号这两种类型都有,他们都是终止进程,有什么区别呢?

我们发现Core中有SIGABRT、SIGFPE、SIGSEGV等等,他们都比较像异常情况。报错的具体代码尚不清楚。需要用户进一步排查

Term中的SIGINT(键盘中断)、SIGKILL(杀死进程)等等,其实他们都没犯错, 只是被杀掉了。结果很清楚

你的代码如果出现了Core类型的错误,其实会发生core dump(核心转储),也就是在当前目录下多出一个以进程pid命名的 core.pid 文件。我们可以通过查看gbd查看代码具体报错位置信息。但是core dump功能是被默认关闭的。

输入指令ulimit -a可以查看系统的配置项,其中第一项core file size就是core dump,大小为0,我们可以将他大小设置一下

输入指令ulimit -c + size,就可以更改core file size 的大小,这是内存级别的,也就是重启xshell会自动恢复。 

 现在再更改代码并运行就会发现多了core dumped,发生了核心转储。

我们现在gdb调试mytest,同时在gdb中输入core-file + core.pid ,此时就可以看到该文件是在具体哪个地方出错。 

 

总结

  • 信号的产生,最终都要由操作系统来进行执行,这是因为操作系统是进程的管理者。
  • 进程在信号到来不会立即处理,而是在合适的时候处理。
  • 由于信号不会被立即处理,因此信号需要暂时被进程记录下来,记录在信号位图中。
  • 信号在没有收到信号的时候,已经知道自己该如何处理信号。
  • 操作系统向进程发送信号,本质是向目标进程的信号位图中写信号(置1)。

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

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

相关文章

最新可用免费VPS云服务器整理汇总

随着云计算技术的不断发展&#xff0c;越来越多的个人和企业开始关注和使用VPS云服务器。VPS云服务器以其高度的灵活性、可定制性和安全性&#xff0c;成为了一种受欢迎的服务器解决方案。然而&#xff0c;对于初学者或者预算有限的用户来说&#xff0c;如何选择合适的免费VPS云…

ZYNQ学习之Ubuntu系统的简单设置与文本编辑

基本都是摘抄正点原子的文章&#xff1a;<领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf&#xff0c;因初次学习&#xff0c;仅作学习摘录之用&#xff0c;有不懂之处后续会继续更新~ 一、Ubuntu的简单操作 1.1 切换拼音输入法 Ubuntu 自带的拼音输入法&#xff0c;有两种…

ADAS多传感器后融合算法解析-下篇

ADAS多传感器后融合算法解析-下篇 在ADAS多传感器后融合(上)中我们介绍了后融合的接口、策略。本文将主要介绍后融合的实现流程、难点及注意事项。 附赠自动驾驶学习资料和量产经验&#xff1a;链接 二、后融合处理流程 如下图为基本RC后融合系统流程图&#xff0c;接下来将…

day 36 贪心算法 part05● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间

一遍过。首先把区间按左端点排序&#xff0c;然后右端点有两种情况。 假设是a区间&#xff0c;b区间。。。这样排列的顺序&#xff0c;那么 假设a[1]>b[0],如果a[1]>b[1]&#xff0c;就应该以b[1]为准&#xff0c;否则以a[1]为准。 class Solution { public:static bo…

argocd部署

一、前言 ArgoCD 是一个开源的、持续交付工具&#xff0c;用于自动化部署应用程序到 Kubernetes 集群。它基于 GitOps 理念&#xff0c;通过使用 Git 作为单一的源头来管理应用程序的配置和部署状态&#xff0c;argocd会定时监控git仓库中的yaml配置文件&#xff0c;当git仓库中…

验证码/数组元素的复制.java

1&#xff0c;验证码 题目&#xff1a;定义方法实现随机产生一个5位的验证码&#xff0c;前面四位是大写或小写的英文字母&#xff0c;最后一位是数字 分析&#xff1a;定义一个包含所有大小写字母的数组&#xff0c;然后对数组随机抽取4个索引&#xff0c;将索引对应的字符拼…

JSON Web Token 入门教程

JSON Web Token&#xff08;JWT&#xff09;是一种可以在多方之间安全共享数据的开放标准&#xff0c;JWT 数据经过编码和数字签名生成&#xff0c;可以确保其真实性&#xff0c;也因此 JWT 通常用于身份认证。这篇文章会介绍什么是 JWT&#xff0c;JWT 的应用场景以及组成结构…

46秒AI生成真人视频爆火,遭在线打假「换口型、声音」

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了人工智能中文站https://ai.weoknow.com 每天给大家更新可用的国内可用chatGPT资源 发布在https://it.weoknow.com 更多资源欢迎关注 是炒作还是真正的 AI 视频能力进化&#xff1f; AI 生成视频已经发展到这个程…

rabbitmq集群问题排查

blowcode-test-redis04、blowcode-test-redis05、blowcode-test-redis06 这3个节点搭建的rabbitmq集群&#xff0c;04是主节点。 某次分别观察3个节点的管理页面&#xff0c;先都只能看到自己的节点是正常的绿色状态&#xff0c;猜测节点都各自为政了。 下图是05节点成功加入0…

iOS_convert point or rect 坐标和布局转换+判断

文章目录 1. 坐标转换2. 布局转换3. 包含、相交 如&#xff1a;有3个色块 let view1 UIView(frame: CGRect(x: 100.0, y: 100.0, width: 300.0, height: 300.0)) view1.backgroundColor UIColor.cyan self.view.addSubview(view1)let view2 UIView(frame: CGRect(x: 50.0, …

Redis面试题-缓存穿透,缓存击穿,缓存雪崩

1、穿透: 两边都不存在&#xff08;皇帝的新装&#xff09; &#xff08;黑名单&#xff09; &#xff08;布隆过滤器&#xff09; 解释&#xff1a;请求的数据既不在Redis中也不在数据库中&#xff0c;这时我们创建一个黑名单来存储该数据&#xff0c;下次再有类似的请求进来…

TikTok养号保姆式操作攻略

TikTok养号的重要性不必多少&#xff0c;不仅可以在创号初期保障账号安全&#xff0c;后期的账号流量也需要以前期养好账号为前提。下面就给大家分享如何养号的真实操作攻略&#xff01; 一、为什么要养号 &#xff08;1&#xff09;提高系统推荐精准度 系统不了解新账户人设…

AtCoder Beginner Contest 337 A - E

A - Scoreboard 大意 高桥队和青木队进行了场比赛&#xff0c;给出每场比赛中高桥队和青木队的积分&#xff0c;问最后谁总分更高或平局。 思路 统计总分比较即可。 代码 #include<iostream> using namespace std; int main(){int n, a0, b0;cin >> n;while(…

报错:ValueError: assignment destination is read-only 的解决方案

运行出现报错&#xff1a; ValueError: assignment destination is read-only 解决方案&#xff1a; 加一个.copy() data open_file(r"G:/21.tif").transpose(2,0,1)data data.copy()

Linux下的多线程编程:原理、工具及应用(5)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;Flower of Life—陽花 0:34━━━━━━️&#x1f49f;──────── 4:46 &#x1f504; ◀️ ⏸ ▶️ ☰ …

python--切片

1.切片&#xff1a; 切片是编程语言为有序序列&#xff08;sequence&#xff09;准备的&#xff0c;用来切割或者截取某个片段 一个完整的切片是包含三个参数和两个冒号" : " ,用于分隔三个参数(start_index、end_index、step)。当只有一个“:”时&#xff0c;默认第…

java设计模式之适配器模式

适配器模式概述 众所周知,我们国家的生活用电的电压是220V,而笔记本电脑、手机等电子设备的工作电压没有这么高,为了使笔记本、手机等设备可以使用220V的生活用电,就需要使用电源适配器(ACAdapter),也就是人们常说的充电器或变压器,有了这个电源适配器,原本不能直接工作…

2024室内设计和建筑必须知道的十大3D渲染趋势!

2023年对建筑圈是非常不平凡的一年&#xff0c;高清视频渲染、元宇宙全覆盖、AI模型大爆发.....不断发展的 3D 数字技术世界正迅速重塑建筑设计行业。 2024年&#xff0c;室内设计和建筑设计领域在3D渲染方面又将迎来怎样的变革&#xff1f;以下十大3D渲染趋势&#xff0c;你不…

代码随想录——搜索插入位置(Leetcode35)

题目链接 class Solution {public int searchInsert(int[] nums, int target) {int len nums.length;int left 0;int right len - 1;int index -1;while(left < len / 2){if(nums[left] target || target < nums[left]){index left;break;}else{left;}if(nums[ri…

详解 WebWorker 的概念、使用场景、示例

前言 提到 WebWorker&#xff0c;可能有些小伙伴比较陌生&#xff0c;不知道是做什么的&#xff0c;甚至不知道使用场景&#xff0c;今天这篇文章就带大家一起简单了解一下什么是 webworker&#xff01; 概念 WebWorker 实际上是运行在浏览器后台的一个单独的线程&#xff0…