【Linux】初识信号及信号的产生

初始信号

  • 初始信号
    • 什么是信号
    • 站在应用角度的信号
    • 查看Linux系统定义的信号列表
  • 信号的常见处理方式
  • 信号的产生
    • 通过终端按键产生信号
      • 什么是core dump?
      • 如何开启core dump?
      • core dump有什么用?
      • 为什么默认关闭core dump?
      • 设置了core文件大小但是没有产生core文件的可能原因
    • 通过系统函数向进程发信号
    • 由软件条件产生信号
    • 硬件异常产生信号
      • 一点简单的拓展,有关于键盘产生信号
      • 关于异常产生信号

初始信号

什么是信号

Linux系统提供的让用户(进程)给其他进程发送异步信息的一种方式

  1. 在没有发生的时候,我们已经知道发生的时候,怎么处理了
  2. 我们可以识别各种类型的信号,结合第一条和第二条,我们能识别一个信号并处理(打个比方说,当我们过马路时看到红灯时,我们眼睛看到了红灯信号,然后我们的处理方式通常就是站在马路边上等待)
  3. 信号到来的时候,我们正在处理更重要的事情,我们暂时不能处理到来的信号,我们必须要将到来的信号进行临时保存
  4. 信号到了,可以不立即处理,自己在合适的时候处理
  5. 信号的产生是随时产生的,我们无法准确预料,所以信号是异步发送的(信号的产生,是由别人(用户、进程)产生的,我收到之前,我一直在忙我的事情,并发在运行的)
    将以上的“我”换成进程,就是进程看待信号的方式

站在应用角度的信号

在这里插入图片描述

  • 用户输入指令,在shell下启动一个前台进程
  • 用户按下ctrl+c,键盘输入产生硬件中断,被OS获取,解释成信号,发送给目标前台进程
  • 前台进程因为收到信号,进而引起进程退出
    在这里插入图片描述
    注意:
    1、 ctrl+c 产生的信号只能发送给前台进程,一个命令后面加上&可以将其放到后台执行,这样shell就不必等待该进程结束就可以接受新的命令,启动新的进程
    2.、shell可以同时接受运行一个前台进程任意多个后台进程,只有前台进程才能接到例如ctrl+c这种控制链产生的信号
    3、 前台进程在运行过程中用户随时可能按下ctrl+c而产生一个信号,也就是说该进程的用户代码空间执行到任何地方都可能因为收到信号而终止或者产生其他行为,所以信号相对于进程的控制流程来说是异步的

查看Linux系统定义的信号列表

在这里插入图片描述

  • 每个信号都有一个编号和一个宏定义名称,比如2号信号就是#define SIGINT 2
  • 编号34以上的是实时信号,这篇博客主要是讨论编号34以下的信号,不讨论实时信号,这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细的说明:在命令行输入man 7 signal即可查看
    在这里插入图片描述

信号的常见处理方式

常见的信号处理方式有以下三种

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

  这里要先介绍一个linux的系统调用signal
在这里插入图片描述
在这里插入图片描述
1、当我们要忽略一个信号时(这里用2号信号为例),就将第二个参数传递SIG_IGN即可
在这里插入图片描述
在这里插入图片描述
2、执行该信号的默认处理动作,2号信号的默认处理动作就是终止当前正在运行的前台进程,这里就不再演示了
3、让该信号执行自定义的动作
在这里插入图片描述
在这里插入图片描述

信号的产生

通过终端按键产生信号

  SIGINT的默认处理动作是终止当前进程,SIGQUIT的默认处理动作是终止进程并Core Dump(之前演示时用到的ctrl+c就是向进程发送2号的方式)
在这里插入图片描述
  进程收到了的大部分信号的动作都是进程自己终止,终止有两种方案,一种叫做core,一种叫做term,它们又什么区别?

什么是core dump?

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

如何开启core dump?

  之前已经提到了core dump默认是关闭的,使用命令ulimit -c可以查看相关的信息
在这里插入图片描述
使用ulimit -c可以通过设置文件大小打开core dump功能
在这里插入图片描述

core dump有什么用?

  当一个进程发生了除0异常,如果是term结束,在系统层面上直接不管了,直接把代码和数据还有内核数据结果直接释放掉,这个进程就没了
  但是如果信号除0动作是core,则会将进程在内存中的核心数据(主要是与调试有关)转储到磁盘中形成core、core.pid的文件,这样可以定位到这个进程为什么会退出,以及是执行到哪一行代码退出了
  core其实是一种机制,如果进程在执行过程中出异常了,就将进程在内核中的核心数据转储到磁盘当中以文件的方式保存,这种方式叫做core dump:核心转储
  所以命令ulimit -c其实是在设置core文件的上限大小(默认情况下为0,代表即便是core退出,也不要形成核心转储文件)
  说了这么多,core文件中既然包含了相关的错误信息,我们就可以根据文件中的错误信息进行调试

int main()
{
    int a=10;
    a/=0;
    return 0;
}

  比如这段代码,在代码中产生一个除0异常,然后运行程序
在这里插入图片描述
发现多了一个文件core,这个文件存的就是程序的错误原因
在这里插入图片描述
  大部分信号当中,只要是退出信息(Action)是core,都是可以通过打开core dump功能,事后根据core文件进行定位问题和调试
云服务器默认是将进程以core形式退出,进行了特定的设定,默认core是被关闭的

为什么默认关闭core dump?

  Linux系统是有服务关闭自动重启的功能的,如果服务一异常关闭,然后重启,一关闭又重启…就会留下很多的core文件,时间一长就会导致云服务器的磁盘被占满->防止未知的core dump一直在进行,导致磁盘服务器被打满

设置了core文件大小但是没有产生core文件的可能原因

  我在第一次使用已经设置了core文件的大小但是出现异常时并没有出现core文件,我查了一下,有以下几种说法

  • 程序设置了用户id(即调用setuid),但当前用户并非该程序文件的所有者
  • 程序设置了组id(即调用setgid),但当前用户并非该程序文件的组所有者
  • 用户没有当前目录或指定core文件产生目录的写权限
  • core文件太大,磁盘空间不足
      但是我检查了这几点发现这些都不是原因,后来我了解到,可能是core文件产生的位置有关,core的缺省位置是程序所在目录,可以通过修改/proc/sys/kernel/core_pattern来指定core文件生成位置了名称。
      然后我查看了core_pattern文件,发现文件内容是一段脚本程序,后来查看说明文件,才知道core_pattern中如果首先指定了一个 ‘|’ 管道符,则会将生成的core文件传递给后面所跟的脚本去处理。
    在这里插入图片描述
      至此,也就确定了问题的原因,| 管道符后面的脚本将我们的core文件给吞了,解决方法自然就是去掉这个脚本,换成自己指定的目录
      但直接去修改core_pattern文件并没有成功,保存时会提示FSync错误,查阅资料得知,这个文件有特殊限制,只能通过命令:
sudo bash -c "echo 这里是写入内容 > /proc/sys/kernel/core_pattern "

我使用的是

sudo bash -c "echo core > /proc/sys/kernel/core_pattern "

  来进行写入,即指定程序所在目录为core文件生成目录,core文件名称为"core"。

通过系统函数向进程发信号

在这里插入图片描述
在这里插入图片描述  kill函数是向任意进程发送信号,而raise是向自己发送信号。两个函数的返回都是成功返回0,错误返回-1
在这里插入图片描述
  abort函数的作用是使当前进程接收到信号而异常重者,和kill(getpid(),6)用法有点相似(6号信号是SIGABRT)

由软件条件产生信号

  SIGPIPE就是很典型的由软件条件产生的信号,这个信号是在进程间通信方式之一——管道中,读端已经关闭而写端仍然还在写入时,这个时候系统就会通过向写端发送SIGPIPE信号关闭写端
  还有个信号SIGALRM信号

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

  调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。
  这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。打个比方,某人要小睡一觉,设定闹钟为30分钟之后响,20分钟后被人吵醒了,还想多睡一会儿,于是重新设定闹钟为15分钟之后响,“以前设定的闹钟时间还余下的时间”就是10分钟。如果seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数
  但是"闹钟"只能响一次,所以如果要让这个闹钟多次响,需要捕捉SIGARM信号,在处理完信号后,再设置一个闹钟

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

int main()
{
    int cnt=0;
    alarm(1);
    while(true)
    {
        std::cout<<cnt<<std::endl;
        cnt++;
    }
    return 0;
}

  这个代码的作用就是在1秒钟之内不停的数数,1秒种到了因接收到了SIGARM就停止

硬件异常产生信号

  硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。

一点简单的拓展,有关于键盘产生信号

  键盘是一个硬件,作为一个键盘它需要知道以下几点

  1. 按键按下了

  2. 哪些按键按下了

  3. 字符输入(字符设备(键盘都是字符输入)),键盘还可以进行组合键输入(ctrl +c),相当于输入的是命令
      不管你是键盘输入还是组合键输入,在键盘层面上,就是按键,但是到底输入的字符还是命令,这个是由操作系统决定的(键盘和OS联合解释),因为一切皆文件,所以键盘设备也可以看作是操作系统打开的一个文件,所以键盘获取到的数据就会放到键盘的输入缓冲区里,上层就通过0号文件描述符将其读出来
      操作系统怎么知道键盘上面有数据输入?
      要么是操作系统去定期的检测键盘是否有数据被按下,但是这样的话效率就太低了
      其实操作系统时使用了一种硬件中断的技术,当操作系统刚开机的时候,已经形成了一张表,这张表上已经注册了很多对软硬件进行操作的方法
      这个所谓的中断向量表就是函数指针数组。此时的CPU正在执行进程代码。这个中断向量表其实也是属于操作系统的数据
      CPU只和内存打交道,并且CPU内部有很多的针脚(物理性的),这些针脚在主板上是可以和键盘进行连接的(每个针脚都有特定的编号),未来键盘在进行按键的时候会给CPU中特定的针脚触发硬件中断,CPU就知道哪个针脚上面有高电平了就可以识别这个针脚。
      总之,CPU已经知道了有触发的针脚上面已经有高电平了,有因为每个针脚上面又有特定的编号,也就意味着当键盘被按下时会向CPU的2号针脚处发送高电平(也可以把这个2号称之为中断号)。即CPU能识别到

  4. 有高电平

  5. 是几号针脚

  CPU内部还有寄存器,寄存器req就会将中断号存起来(到此,硬件到软件的动作就做完了)
  然后,CPU识别到对应的寄存器中有数字,CPU就直接要求操作系统先暂停当前进程,然后让操作系统拿着中断号去中断向量表去查对应的方法,然后根据中断向量表中对应的方法去执行读取数据的任务。因为中断向量表中的方法都是操作向量表提供的,所以在调用里面的方法的时候,操作系统就能够知道数据到来了并将数据读入内存中
  读到数据之后就要对数据做“判定”,看是字符还是控制命令,如果是字符,就将其放入到缓冲区中让上层读取;如果是控制命令,就将其解释成信号,让后再将这个信号发送给进程(解释信号就是到进程的pcb中将位图上对应的比特位由0置1)
  之前提到,当信号在到来的时候,如果进程正在处理更重要的事情,就会暂时不处理信号,而是将信号进行临时保存,保存在哪里呢?保存在进程的pcb中。一个进程可能会收到多个信号,所以pcb内部就需要对收到的信号进行管理,因为信号的编号是1、2……31,所以pcb中采用的就是位图的方法保存信号

关于异常产生信号

emsp; CPU中有很多寄存器,有些寄存器是用来做计算的,也有些寄存器是用来CPU内部中的管理,其中就有一个寄存器叫做EFLAGS/RFLAGS,这个是标志寄存器,包含了状态和控制标志,其中有一个标志称为CF(这个标志称作为是溢出标志,Overfliow Flag),当CPU内部进行运算

int a=10;
a/=0;

  CPU内部会将10放到一个寄存器中(假设为eax),然后将0放到一个寄存器中(假设为ebx),按照代码就是让eax中数初一abx中的数,然后将结果写回到eax中,但是在运算10除以0的时候,得到的是一个巨大的数字,据发生了溢出,然后溢出标志位设为1,也就是说计算出现了错误(计算错误,表现到了CPU的寄存器上也就是硬件上),此时操作系统识别到了操作系统内部有错误,CPU就不再调度进程了,CPU就告诉操作系统,操作系统发现确实出现了异常,就直接向对应进程的pcb中发送对应的溢出信号(修改对应的位图),至此,就完成了信号的发送

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

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

相关文章

贪心,CF802B. Heidi and Library

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 Problem - 802A - Codeforces 二、解题报告 1、思路分析 这个题相当于你有一个容量为K的Cache&#xff0c;然后给你一系列访存序列 当访问缺失时你不得不替换掉Cache中某些块 学过操作系统都很熟悉页面置…

The Isle恐龙岛服务器开服联机教程

服务端区别&#xff1a;The lsle 是测试服 &#xff1b;The lsle Evrima 是正式服&#xff08;运行内存需要上到12G才可以运行&#xff09; 1、购买后登录服务器 进入控制面板后会出现正在安装的界面&#xff0c;安装大约5分钟&#xff08;如长时间处于安装中请联系我们的客服人…

LeetCode216组合总和3

题目描述 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a;只使用数字1到9。每个数字 最多使用一次。返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 解析 递归加剪枝&#xff0c;搜索长度达…

基于 Amazon EC2 快速部署 Stable Diffusion WebUI + chilloutmax 模型

自2023年以来&#xff0c;AI绘图已经从兴趣娱乐逐渐步入实际应用&#xff0c;在众多的模型中&#xff0c;作为闪耀的一颗明星&#xff0c;Stable diffusion已经成为当前最多人使用且效果最好的开源AI绘图软件之一。Stable Diffusion Web UI 是由AUTOMATIC1111 开发的基于 Stabl…

【数字孪生平台】光幻示例解析

本文在线示例查看。更多精彩内容尽在数字孪生平台,关注公众号:sky的数孪技术,技术交流、源码下载请添加VX:digital_twin123 地形构建 我们目的要搭建一个中间平坦、两侧有凹凸山脉效果并且能够一直绵延不断的地形,接下来我们通过三个问题来进行分析。 采用什么样的几何图…

Vue——模板引用(不建议使用,了解)

文章目录 前言测试案例 前言 模板引用&#xff0c;在官方文档中也有很详细的描述。 虽然 Vue 的声明性渲染模型为你抽象了大部分对 DOM 的直接操作&#xff0c;但在某些情况下&#xff0c;我们仍然需要直接访问底层 DOM 元素。 个人理解为&#xff1a; 在vue中&#xff0c;依据…

Scrum团队在迭代中如何处理计划外的工作

认为 Scrum 团队不做计划其实是一个误区&#xff0c;实际上很多 Scrum 团队在冲刺计划会议以及在细化工作项时均会进行详细规划。此外&#xff0c;他们还会创建一个路线图&#xff0c;以便显示他们在多个冲刺中的计划。 Scrum 团队需要经常进行计划&#xff0c;以便在不断变化…

本地 Java API 访问云上 HDFS 集群的问题与解决

前言 这篇文章默认是已经在云上配置好了 Haoop 集群&#xff0c;因此本文主要是记录一些可能会出现错误的地方。 如果还不会配置 Hadoop 集群&#xff0c;那么可以参考本专栏的另一篇文章&#xff1a;云上配置 Hadoop 集群详解 另外在进行本文的学习之前也建议先看看该文章&…

创意设计新伙伴:StartAI PSAI插件,让设计工作更轻松!

在设计的世界里&#xff0c;灵感与效率是设计师的双翼。但有时候&#xff0c;面对复杂的设计任务和紧迫的截止日期&#xff0c;即使是最富有经验的设计师也会感到力不从心。StartAI&#xff0c;一款革命性的PS AI设计插件。 StartAI&#xff1a;设计工作的加速器 StartAI是一款…

超分辨重建——SRGAN网络训练自己数据集与推理测试(详细图文教程)

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

Linux——简单指令汇总

Linux&#xff0c;一般指GNU/Linux&#xff0c;是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹&#xff08;Linus Benedict Torvalds&#xff09;于1991年10月5日首次发布&#xff0c;它主要受到Minix和Unix思想的启发&#xff0c;是一个…

笔记-python操作kafka实践

1、先看最简单的场景&#xff0c;生产者生产消息&#xff0c;消费者接收消息&#xff0c;下面是生产者的简单代码。 #!/usr/bin/env python # -*- coding: utf-8 -*- import json from kafka import KafkaProducerproducer KafkaProducer(bootstrap_serversxxxx:x)msg_dict …

浅测 长亭雷池 WAF “动态防护”

本文首发于 Anyeの小站 前言 雷池 WAF 社区版的更新速度是真快啊&#xff0c;几乎一周一个小版本&#xff0c;俩月一个大版本&#xff0c;攻城狮们真的狠啊&#xff0c;没法测了。 废话不多说&#xff0c;前两天看到了 这篇文章&#xff0c;对雷池的“动态防护”功能挺感兴趣…

二人订单共享模式:新零售电商盈利新秘诀

电商江湖日新月异&#xff0c;竞争如火如荼&#xff0c;如何脱颖而出&#xff0c;赢得消费者&#xff1f;二人订单共享模式&#xff0c;这是一种全新的商业模式&#xff0c;旨在打造爆款产品&#xff0c;迅速吸引大量客源&#xff0c;并激发消费者重复购买欲望。 首先&#xf…

期权懂带你懂50etf认沽期权和认购期权有什么区别?

今天带你了解期权懂带你懂50etf认沽期权和认购期权有什么区别&#xff1f;在金融市场中&#xff0c;期权是一种允许持有者在未来某个时间以特定价格买入或卖出基础资产的金融衍生品。 50etf认沽期权和认购期权有什么区别&#xff1f; 50ETF认沽期权和认购期权的主要区别在于它…

从报名到领证:软考高级【网络规划设计师】报名考试全攻略

本文共计10551字&#xff0c;预计阅读35分钟。包括七个篇章&#xff1a;报名、准考证打印、备考、考试、成绩查询、证书领取及常见问题。 不想看全文的可以点击目录&#xff0c;找到自己想看的篇章进行阅读。 一、报名篇 报名条件要求&#xff1a; 1.凡遵守中华人民共和国宪…

淘宝电商接口获取商品数据,该怎么获取?

淘宝电商接口&#xff08;也称为淘宝开放平台API&#xff09;允许开发者通过编程方式获取淘宝平台上的商品数据、订单数据等。然而&#xff0c;直接获取淘宝的商品数据并不是一件简单的事情&#xff0c;因为淘宝对API的使用有一定的限制和要求&#xff0c;包括权限申请、接口调…

项目-双人五子棋对战: websocket的讲解与使用 (1)

项目介绍 接下来, 我们将制作一个关于双人五子棋的项目, 话不多说先来理清一下需求. 1.用户模块 用户的注册和登录 管理用户的天梯分数, 比赛场数, 获胜场数等信息. 2.匹配模块 依据用户的天梯积分, 实现匹配机制. 3.对战模块 把两个匹配到的玩家放到同一个游戏房间中, 双方通…

线程进阶-2 ThreadLocal

一.简单说一下ThreadLocal 1.ThreadLocal是一个线程变量&#xff0c;用于在并发条件下&#xff0c;为不同线程提供相互隔离的变量存储空间。在多线程并发的场景下&#xff0c;每个线程往ThreadLocal中存的变量都是相互独立的。 2.基本方法 &#xff08;1&#xff09;set(Obj…

wms中对屏幕进行修改wm size设置屏幕宽高原理剖析

背景&#xff1a; 上面是正常屏幕1440x2960的屏幕大小&#xff0c;如果对display进行相关的修改&#xff0c;可以使用如下命令&#xff1a; adb shell wm size 1080x1920 得出如下的画面 明显看到差异就是屏幕上下有黑边了&#xff0c;那么下面就来调研这个wm size是怎么做的…