Linux信号:信号的概念及意义

C+五条 2024-06-16 09:07:04 阅读 57

目录

一、什么是信号

kill-l查看信号

二、信号的产生

2.1系统调用

kill

raise

abort

2.2软件条件

13)SIGPIPE pipe信号

14)SIGAKARM alarm信号

2.2硬件中断

2.3异常

8)SIGFPE 除0异常

11)SIGSEGV 野指针

2.4信号处理的常见方式

三、Core Dump和term

core

term


一、什么是信号

在日常生活中有很多和信号有关的例子,红绿灯不同的颜色代表不同的信号,汽车碰到人按喇叭代表提醒你有车的信号,跑步枪响代表跑步的信号,我们不知道信号合适会出现,但在信号出现时,我们都知道此信号代表着我们应该进行什么样的动作,而在linux操作系统中亦是如此,只不过此时发出信号的一方变成了OS或者是用户,接收信号量的一方变成了进程。 而在Linux中的信号则具有以下几种特征,也是进程看待信号的方式: Linux系统提供的让用户(进程)给其他进程发送异步信息的一种方式 1、在没有发生的时候,我们已经知道发生的时候该怎么处理了。 2、信号我们能够认识,很早之前就已经被设置了识别特别待定信号的方式。 3、信号到来的时候,正在处理更重要的事情,暂时不能处理到来的信号,必须暂时要将到来的信号进行临时保存(保存在进程PCB中)。 4、信号到了,可以不立即处理,可以在合适的时候处理。 5、信号的产生是随时产生的,我们无法准确预料,所以信号是异步发送的。 信号的产生是由别人(用户/进程)产生的,收到之前,该进程一直在执行自己的代码,所以是并发在跑的。

kill-l查看信号

二、信号的产生

2.1系统调用

系统调用作为C/C++学习过程中是必不可少的一个内容,因为安全性和操作系统的规则,用户想要执行某些系统层面的操作时,必须通过系统调用来让操作系统执行,而之前提到的kill指令就是通过系统调用来实现的。

kill

 通过kill可以向任意的进程发送任意的信号。

raise

自己给运行自己的进程发送信号。

abort

终止自己,向自己发送6号信号。

2.2软件条件

13)SIGPIPE pipe信号

在博主之前的文章中曾详细介绍过pipe的使用,管道是一个文件,本质是软件,管道写端退出了,读端一直在读,操作系统就会认为条件不满足,就会发13号信号让该进程退出。

14)SIGAKARM alarm信号

 设置一个闹钟,到了时间执行对应指令,默认动作时term终止进程。

#include <unistd.h>unsigned int alarm(unsigned int seconds);调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。 这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。打个比方,某人要小睡一觉,设定闹钟为30分钟之后响,20分钟后被人吵醒了,还想多睡一会儿,于是重新设定闹钟为15分钟之后响,“以前设定的闹钟时间还余下的时间”就是10分钟。如果seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数。

alarm(0) 取消闹钟

闹钟函数是一个系统调用,设定闹钟,本质是在OS内部设定的,操作系统要定期将用户级的数据从缓冲区刷新到外设,此时就要求操作系统具有定时功能, 所以操作系统内部存在很多闹钟,所以就需要先描述再组织,此时就有一个alarm结构体,而判断闹钟是否到了时间只需要将闹钟设置的时间和现在的时间进行比较,如果时间到了就触发,所以我们可以建立一个最小堆,每次只需要判断堆顶的数据是否超时就可以。

2.2硬件中断

1. 用户输入命令,在Shell下启动一个前台进程。 用户按下Ctrl-C ,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程前台进程因为收到信号,进而引起进程退出。 而键盘是如何转变为信号从而被进程识别的呢? 首先键盘按下以后有两种情况,一种是正常作为 字符输入,一种是 组合键输入, 组合键输入的是命令。由OS来判断输入的是字符还是命令。而操作系统得知是否有数据输入就是采用中断的方式。 OS中存在一个中断向量表,CPU在执行代码时如果用户输入组合键,CPU就会有特定的针脚收到键盘传来的高电频,从而触发硬件中断,而每个针脚都有编号,而这个编号就叫中断号,然后将中断号放到寄存器中,然后OS拿着中断号去向量表执行相关方法,然后将字符放到键盘缓冲区。 如果输入的ctrl+c OS就把其解释为2号信号然后发给进程  。 硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。         

2.3异常

8)SIGFPE 除0异常

11)SIGSEGV 野指针

2.4信号处理的常见方式

1. 忽略此信号。 2. 执行该信号的默认处理动作。 3. 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号。

三、Core Dump和term

首先解释什么是Core Dump。当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部 保存到磁盘上,文件名通常是core,这叫做Core Dump。进程异常终止通常是因为有Bug,比如非法内存访问导致段错误,事后可以用调试器检查core文件以查清错误原因,这叫做Post-mortem Debug(事后调试)。一个进程允许产生多大的core文件取决于进程的Resource Limit(这个信息保存 在PCB中)。默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件。 首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K: $ ulimit -c1024。

在Linux信号中,绝大部分信号都会执行core或term,其效果都是终止进程,那么二者之间有什么区别呢。

core

比如代码发生除0错误时就会引发core,此时编译器会报错,但在当前目录下依旧会形成可执行文件,此时执行可执行文件就会出现Float Point exception 也就是除0错误。

ulimit-a查看core是否被打开

ulimit-c num打开core dump功能,num按需求去取,单位是block,此时当前目录下就会形成一个core文件。

再次运行除零错误的代码依旧会报错,Float Point exception (core dumped)。

所以为什么要有core文件呢?OS可以通过core文件定位到进程为什么退出,以及执行到哪一行退出的。

core文件是什么呢?将进程在内存中的核心数据(与调试有关)转储到磁盘中形成core/core.pid的文件。

而core文件的功能就是协助我们进行调试。

以下运行一个代码,假设代码中包含除0错误,生成可执行后,gdb可执行程序,输入 core-file指令就会显示出代码出问题的行数。

  这种方式也叫事后调试。

而云服务器一般都是默认关闭核心转储功能,也就是默认将进程core退出,进行了特定的设定,默认core是被关闭的。

在线上服务中,最重要的就是让服务功能持续的跑起来,而一旦代码出现问题,如果此时core是开启的就会在当前路径下形成一个core文件,core文件也是很大的,如果问题没有得到及时的解决,可能os就会一直形成core文件,从而不断的占用磁盘空间。主要是防止未知的core dump一直在进行。

而在unbuntu中即使打开了core也不会像centos下在core文件后缀pid,这样即使一直生成core文件也只会在当前目录下反复覆盖生成一个core,就很好的规避了上述问题。

 而在进程控制中的这个core dump标志就表示是否发生了核心转储,为0表示没有发生,1表示发生了。 

term

term就是正常的直接退出



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。