当前位置: 首页 > news >正文

【Linux】学习-进程信号

进程信号

信号入门

生活角度的信号

  • 你在网上买了很多件商品,再等待不同商品快递的到来。但即便快递没有到来,你也知道快递来临时,你该怎么处理快递。也就是你能“识别快递”,也就是你意识里是知道如果这时候快递员送来了你的包裹,你知道该如何处理这些包裹
  • 当快递员到了你楼下,你也收到快递到来的通知,但是你正在打游戏,需5min之后才能去取快递。那么在在这5min之内,你并没有下去去取快递,但是你是知道有快递到来了。也就是取快递的行为并不是一定要立即执行,可以理解成“在合适的时候去取”。你可以暂时将包裹搁置,等到有空的时候再处理。
  • 在收到通知,再到你拿到快递期间,是有一个时间窗口的,在这段时间,你并没有拿到快递,但是你知道有一个快递已经来了。本质上是你“记住了有一个快递要去取”
  • 当你时间合适,顺利拿到快递之后,就要开始处理快递了。而处理快递一般方式有三种:1. 执行默认动作(幸福的打开快递,使用商品)2. 执行自定义动作(快递是零食,你要送给你你的女朋友)3. 忽略快递(快递拿上来之后,扔掉床头,继续开一把游戏)
  • 快递到来的整个过程,对你来讲是异步的,你不能准确断定快递员什么时候给你打电话

技术应用角度的信号

什么是Linux信号?

  • 信号是进程之间事件异步通知的一种方式,属于软中断

  • 信号本质是一种通知机制,用户or操作系统通过发送一定的信号,通知进程,某些事件已经发生,进程可以根据信号的种类来进行相关处理、

结合生活信号,对信号的一些小结论

  • 进程要处理信号,必须具备信号的“识别”能力,和此能力是程序员给进程植入的,可以理解成出生就自带的
  • 信号种类繁多,因此进程收到信号后,有可能是立即执行的,也有可能是后续处理的
  • 信号能够被进程所保存,因此也就具备后续处理的能力
  • 一般而言,信号的产生相对于进程而言是异步的,也就是说,信号发送的时候,进程是正在干自己的事情的,随时都有可能收到信号,具备识别能力但不代表提前得知

先简单理解一下信号被进程保存

  • 进程内部有相关的数据结构位图,信号每次被发送给进程时,此时信号处于未决状态,那么用来保存信号的字段表中信号编号对应的位置就会由0变1

    信号处理的三种方式

  • 默认处理

  • 忽略

  • 自定义捕捉

产生信号

通过终端按键产生信号

  • 我们平常在写代码时,其实经常都有在跟信号接触,看以下代码:

    #include <stdio.h>
    #include <unistd.h>
    int main()
    {while(1){printf("I am a process, I am waiting signal!\n");sleep(1);}
    }
    

    image-20231008160048771

由于没有退出条件,因此进程一直处于死循环,此时我们在键盘里键入:Ctrl+c 能够将进程终止,其实按下组合键后本质就是向当前在前台运行的进程发送了终止信号,进程也立马对此信号做出了反应,终止掉了进程。这就是产生信号的其中一种方式

常见信号

  • 信号一共有61个信号,32,33,0号信号是不存在的,而1-31的信号称为普通信号,32-64为实时信号,我们只学习普通信号:

    image-20231008160757094

  • 关于信号的详细信息我们可以用man手册查看:man 7 signal

    image-20231008160703067

  • 每个信号的编号都是被宏定义好的:

    /* Signals.  */
    #define	SIGHUP		1	/* Hangup (POSIX).  */
    #define	SIGINT		2	/* Interrupt (ANSI).  */
    #define	SIGQUIT		3	/* Quit (POSIX).  */
    #define	SIGILL		4	/* Illegal instruction (ANSI).  */
    #define	SIGTRAP		5	/* Trace trap (POSIX).  */
    #define	SIGABRT		6	/* Abort (ANSI).  */
    #define	SIGIOT		6	/* IOT trap (4.2 BSD).  */
    #define	SIGBUS		7	/* BUS error (4.2 BSD).  */
    #define	SIGFPE		8	/* Floating-point exception (ANSI).  */
    #define	SIGKILL		9	/* Kill, unblockable (POSIX).  */
    #define	SIGUSR1		10	/* User-defined signal 1 (POSIX).  */
    #define	SIGSEGV		11	/* Segmentation violation (ANSI).  */
    #define	SIGUSR2		12	/* User-defined signal 2 (POSIX).  */
    #define	SIGPIPE		13	/* Broken pipe (POSIX).  */
    #define	SIGALRM		14	/* Alarm clock (POSIX).  */
    #define	SIGTERM		15	/* Termination (ANSI).  */
    #define	SIGSTKFLT	16	/* Stack fault.  */
    #define	SIGCLD		SIGCHLD	/* Same as SIGCHLD (System V).  */
    #define	SIGCHLD		17	/* Child status has changed (POSIX).  */
    #define	SIGCONT		18	/* Continue (POSIX).  */
    #define	SIGSTOP		19	/* Stop, unblockable (POSIX).  */
    #define	SIGTSTP		20	/* Keyboard stop (POSIX).  */
    #define	SIGTTIN		21	/* Background read from tty (POSIX).  */
    #define	SIGTTOU		22	/* Background write to tty (POSIX).  */
    #define	SIGURG		23	/* Urgent condition on socket (4.2 BSD).  */
    #define	SIGXCPU		24	/* CPU limit exceeded (4.2 BSD).  */
    #define	SIGXFSZ		25	/* File size limit exceeded (4.2 BSD).  */
    #define	SIGVTALRM	26	/* Virtual alarm clock (4.2 BSD).  */
    #define	SIGPROF		27	/* Profiling alarm clock (4.2 BSD).  */
    #define	SIGWINCH	28	/* Window size change (4.3 BSD, Sun).  */
    #define	SIGPOLL		SIGIO	/* Pollable event occurred (System V).  */
    #define	SIGIO		29	/* I/O now possible (4.2 BSD).  */
    #define	SIGPWR		30	/* Power failure restart (System V).  */
    #define SIGSYS		31	/* Bad system call.  */
    #define SIGUNUSED	31
    
  • 其中,Ctrl+c 组合键对应的就是2号信号SIGINT,它所对应的Action行为是Term行为:Terminate终止动作

注意

  1. Ctrl-C 产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。
  2. Shell可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl-C 这种控制键产生的信号。
  3. 前台进程在运行过程中用户随时可能按下 Ctrl-C 而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到 SIGINT 信号而终止,所以信号相对于进程的控制流程来说是异步(Asynchronous)的。

如何理解组合键变信号?

  • 键盘的工作方式是通过中断方式进行的,因此操作系统能读取并解析组合键,解析完毕后会查找进程列表中在前台运行的进程,并把对于的信号写入进程!

初始信号捕捉

我们前面提到过,信号被写入进程后,进程对此信号的处理有三种方式,我们先来简单介绍一下自定义捕捉方式

介绍signal函数

  • image-20231008165135410

    功能:能够捕捉指定的信号编号为signum的信号,然后将此信号的处理方式使用我们自定义的方式handler

  • 其中:sighandler_t是一个函数指针,以一个的函数指针作为另一个函数的参数并在函数内使用函数指针调用对应指向的函数,此函数称为回调函数,自定义捕捉时,我们实现自定义函数,并将函数作为参数传给signal,通过回调的方式,来修改对应信号的捕捉方法。返回值是自定义捕捉前的函数的地址。

通过信号捕捉的方式,验证Ctrl+c组合键是SIGINT信号

  • #include <iostream>
    #include <unistd.h>
    #include <signal.h>
    using namespace std;
    void cathSig(int signum)
    {cout<<"i catch you! SIGINT!"<<endl;
    }
    int main()
    {signal(SIGINT,cathSig);while(1){cout<<"my pid:"<<getpid()<<endl;sleep(1);}
    }
    

image-20231008171152188

我们可以观察到,按下Ctrl-c后进程并不会像之前一样退出,而是执行了我们自己的代码!得以验证以下两个结论:

  • Ctrl-c对应的信号为SIGINT信号
  • Ctrl-c对应的信号处理方式为终止进程,自定义捕捉方式后,原先的处理方法就被舍弃了

注意

  • signal函数一般写在最前面,原理类似于我们要先买票,才能对信号进行自定义捕捉,后面讲阻塞信号时会解释原理!

Core Dump

我们先来比较两个信号

  • image-20231008171758567

    这两个信号都是从键盘敲组合键来向进程发送信号,其中:

    • Ctrl-c 对应的是2号SIGINT
    • Ctrl-\ 对应的是3号信号SIGQUIT
  • 他们两个的作用都能够用来终止进程,但不同的是:

    2号对应的行为是Term:Terminate

    3号对应的行为是Core:Core Dump

  • 简单验证:image-20231008172753177

什么是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: $ ulimit -c1024

使用命令ulimit命令查看并修改相关资源配置

  • image-20231008173314127

显示0时,代表核心转储不被允许产生,我们需要自行开启:

image-20231008173420309

此时已显示core文件允许的最大内存为1024K,但仅仅在当前会话生效,退出会话后就失效了

  • ulimit命令改变了Shell进程的Resource Limit,test进程的PCB由Shell进程复制而来,所以也具 有和Shell进程相同的Resource Limit值,这样就可以产生Core Dump了。

验证Ctrl-\ 发送的SIGQUIT能够产生core文件的功能

  • 先写一个死循环程序:

    int main()
    {
    while(1)
    {printf("my pid:%d\n",getpid());sleep(1);
    }
    }
    

    运行并用Ctrl-c命令终止后发现并没有产生任何文件:

    image-20231009100614215

  • 再次运行并使用Ctrl-\ 命令终止:

    image-20231009101004912

    这次我们发现产生了core.27213文件,并且后缀就是以进程的pid来命名的,代表此文件就是此进程出现某种异常时,由os将此进程在内核中相关的核心数据转存到磁盘中

核心转储有什么用?

  • 主要是用来进行调试,有了核心转储的数据,调试时会方便很多

利用核心转储进行调试

  • 除了SIGQUIT信号的行为是core,还有其他很多命令也有core行为,下面我们使用SIGFPE信号来验证使用核心转储调试时是否会方便image-20231009103130248

    FPE:Floating point exception指的是浮点数错误,一般指除0错误

  • 首先编写程序,并且编译时,带上-g选项,生成debug文件

    int main()
    {while (1){printf("my pid:%d\n", getpid());sleep(1);int a=100;a/=0;printf("run here...\n");}
    }
    

    image-20231009103412230

  • 重新运行程序,此时也随之生成了core dump文件

    image-20231009103454313

  • 启用gdb调试程序,输入core-file core.pid(core文件名)

    image-20231009103654527

此时我们能发现,在core dump文件的帮助下,能自动帮我们定位在哪一行代码收到了什么信号,比如这里,我们在29行除0错误处收到了8号信号,而8号信号就是对应的SIGFPE信号

core dump标记位

  • 其实我们在进程间控制时就已经和Core Dump有过一面之缘了,我们来看这张图:

在进程控制一篇提到过,子进程退出时,父进程可以通过进程等待的方式,收集子进程的退出信息,以防子进程变成僵尸进程,其中进程等待可以使用wait和waitpid系统调用image-20231009104433908

其中我们也提到过status参数是一个输出型参数,其中如果子进程是被信号所杀的话,此参数的低七位会被填入终止信号的编号,而第八位则是显示是否有生成core dump文件,我们也可以通过代码来验证一下:

用子进程验证core dump标记位

  • int main()
    {pid_t id = fork();if (id == 0){// childsleep(1);int a = 100;a /= 0;exit(0);}int status = 0;waitpid(id, &status, 0);cout << "father:" << getpid()<<" " << "child:" << id <<" "<< "exit sig:" 

相关文章:

【Linux】学习-进程信号

进程信号 信号入门 生活角度的信号 你在网上买了很多件商品,再等待不同商品快递的到来。但即便快递没有到来,你也知道快递来临时,你该怎么处理快递。也就是你能“识别快递”,也就是你意识里是知道如果这时候快递员送来了你的包裹,你知道该如何处理这些包裹当快递员到了你…...

webgis后端安卓系统部署攻略

目录 前言 一、将后端项目编译ARM64 二、安卓手机安装termux 1.更换为国内源 2.安装ssh远程访问 3.安装文件远程访问 三、安装postgis数据库 1.安装数据库 2.数据库配置 3.数据导入 四、后端项目部署 五、自启动设置 总结 前言 因为之前一直做的H5APP开发&#xf…...

【数据分享】1929-2023年全球站点的逐日平均风速数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、能见度等指标&#xff0c;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 有关气象指标的监测站点数据&#xff0c;之前我们分享过1929-2023年全球气象站…...

【多模态大模型】视觉大模型SAM:如何使模型能够处理任意图像的分割任务?

SAM&#xff1a;如何使模型能够处理任意图像的分割任务&#xff1f; 核心思想起始问题: 如何使模型能够处理任意图像的分割任务&#xff1f;5why分析5so分析 总结子问题1: 如何编码输入图像以适应分割任务&#xff1f;子问题2: 如何处理各种形式的分割提示&#xff1f;子问题3:…...

Shell之sed

sed是什么 Linux sed 命令是利用脚本来处理文本文件。 可依照脚本的指令来处理、编辑文本文件。主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。 sed命令详解 语法 sed [-hnV][-e <script>][-f<script文件>][文本文件] sed [-nefr] [动作…...

AJAX——认识URL

1 什么是URL&#xff1f; 统一资源定位符&#xff08;英语&#xff1a;Uniform Resource Locator&#xff0c;缩写&#xff1a;URL&#xff0c;或称统一资源定位器、定位地址、URL地址&#xff09;俗称网页地址&#xff0c;简称网址&#xff0c;是因特网上标准的资源的地址&…...

《Docker极简教程》--Docker环境的搭建--在Linux上搭建Docker环境

更新系统&#xff1a;首先确保所有的包管理器都是最新的。对于基于Debian的系统&#xff08;如Ubuntu&#xff09;&#xff0c;可以使用以下命令&#xff1a;sudo apt-get update sudo apt-get upgrade安装必要的依赖项&#xff1a;安装一些必要的工具&#xff0c;比如ca-certi…...

开源微服务平台框架的特点是什么?

借助什么平台的力量&#xff0c;可以让企业实现高效率的流程化办公&#xff1f;低代码技术平台是近些年来较为流行的平台产品&#xff0c;可以帮助很多行业进入流程化办公新时代&#xff0c;做好数据管理工作&#xff0c;从而提升企业市场竞争力。流辰信息专业研发低代码技术平…...

C#系列-C#操作UDP发送接收数据(10)

在C#中&#xff0c;发送UDP数据并接收响应通常涉及创建两个UdpClient实例&#xff1a;一个用于发送数据&#xff0c;另一个用于接收响应。以下是发送UDP数据并接收响应的示例代码&#xff1a; 首先&#xff0c;我们需要定义一个方法来发送UDP数据&#xff0c;并等待接收服务器…...

突破编程_C++_面试(基础知识(10))

面试题29&#xff1a;什么是嵌套类&#xff0c;它有什么作用 嵌套类指的是在一个类的内部定义的另一个类。嵌套类可以作为外部类的一个成员&#xff0c;但它与其声明类型紧密关联&#xff0c;不应被用作通用类型。嵌套类可以访问外部类的所有成员&#xff0c;包括私有成员&…...

初步探索Pyglet库:打造轻量级多媒体与游戏开发利器

目录 pyglet库 功能特点 安装和导入 安装 导入 基本代码框架 导入模块 创建窗口 创建控件 定义事件 运行应用 程序界面 运行结果 完整代码 标签控件 常用事件 窗口事件 鼠标事件 键盘事件 文本事件 其它场景 网页标签 音乐播放 图片显示 祝大家新…...

【npm】安装全局包,使用时提示:不是内部或外部命令,也不是可运行的程序或批处理文件

问题 如图&#xff0c;明明安装Vue是全局包&#xff0c;但是使用时却提示&#xff1a; 解决办法 使用以下命令任意一种命令查看全局包的配置路径 npm root -g 然后将此路径&#xff08;不包括node_modules&#xff09;添加到环境变量中去&#xff0c;这里注意&#xff0c;原…...

Go 语言 for 的用法

For statements 本文简单翻译了 Go 语言中 for 的三种用法&#xff0c;可快速学习 Go 语言 for 的使用方法&#xff0c;希望本文能为你解开一些关于 for 的疑惑。详细内容可见文档 For statements。 For statements with single condition 在最简单的形式中&#xff0c;只要…...

熵权法Python代码实现

文章目录 前言代码数据熵权法代码结果 前言 熵权法做实证的好像很爱用&#xff0c;matlab的已经实现过了&#xff0c;但是matlab太大了早就删了&#xff0c;所以搞一搞python实现的&#xff0c;操作空间还比较大 代码 数据 import pandas as pd data [[100,90,100,84,90,1…...

浏览器提示ERR_SSL_KEY_USAGE_INCOMPATIBLE解决

ERR_SSL_KEY_USAGE_INCOMPATIBLE报错原因 ERR_SSL_KEY_USAGE_INCOMPATIBLE 错误通常发生在使用 SSL/TLS 连接时,指的是客户端和服务器之间进行安全通信尝试失败,原因是证书中的密钥用途(Key Usage)或扩展密钥用途(Extended Key Usage, EKU)与正在尝试的操作不兼容。这意味…...

使用深度学习进行“序列到序列”分类

目录 加载序列数据 定义 LSTM 网络架构 测试 LSTM 网络 此示例说明如何使用长短期记忆 (LSTM) 网络对序列数据的每个时间步进行分类。 要训练深度神经网络以对序列数据的每个时间步进行分类,可以使用“序列到序列”LSTM 网络。通过“序列到序列”LSTM 网络,可以对…...

Python和Java的区别(不断更新)

主要通过几个方面区分Python和Java&#xff0c;让大家有一个对比&#xff1a; 语言类型 Java是一种静态类型、编译型语言。 Python是一种动态类型、解释型语言&#xff0c;注重简洁和灵活的语法。 语法 在Java中&#xff0c;变量需要显式地声明&#xff0c;指定其类型。例如&am…...

Ubuntu22.04 gnome-builder gnome C 应用程序习练笔记(三)

八、ui窗体创建要点 .h文件定义(popwindowf.h)&#xff0c; TEST_TYPE_WINDOW宏是要创建的窗口样式。 #pragma once #include <gtk/gtk.h> G_BEGIN_DECLS #define TEST_TYPE_WINDOW (test_window_get_type()) G_DECLARE_FINAL_TYPE (TestWindow, test_window, TEST, WI…...

vue electron 应用在windows系统上以管理员权限打开应用

打开package.json文件&#xff0c;在build下的win增加配置 "requestedExecutionLevel": "requireAdministrator",...

c实现链表

目录 c实现链表 链表的结构定义&#xff1a; 链表的结构操作&#xff1a; 1、初始化链表 2、销毁链表 3、插入结点 4、输出链表数据 5、查找链表数据 扩展 代码实现 c实现链表 链表的结构定义&#xff1a; /*** 链表结构定义 ***/ typedef struct Node {int data; //…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...

React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构

React 实战项目&#xff1a;微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇&#xff01;在前 29 篇文章中&#xff0c;我们从 React 的基础概念逐步深入到高级技巧&#xff0c;涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...