【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)
        {
         
            // child
            sleep(1);
            int a = 100;
            a /= 0;
            exit(0);
        }
        int status = 0;
        waitpid(id, &status, 0);
        cout 
        << "father:" << getpid()<<" " 
        << "child:" << id <<" "
        << "exit sig:" 

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

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

相关文章

2.13 数组练习

1、选择题 1.1、若有定义语句&#xff1a;int a[3][6]; &#xff0c;按在内存中的存放顺序&#xff0c;a 数组的第10个元素是 B A&#xff09;a[0][4] B) a[1][3] C)a[0][3] D)a[1][4] 解析&#xff1a;二维数组在内存中是以行优先的方式存放的。这意味着首先填充第一行的…

读十堂极简人工智能课笔记01_人工智能简史

1. 2400年前 1.1. 希腊罗德岛 1.1.1. 是个神奇的岛屿&#xff0c;以机械发明著称&#xff0c;包括真人大小的、大理石制成的自动机 1.1.2. 早在罗马帝国诞生之前&#xff0c;公元前400多年的希腊就有这样的机器人技术&#xff0c;似乎不可思议 2. 公元前970到前931年 2.1.…

LeetCode:83和82.删除排序链表中的重复元素I,II

这两题算是链表的基础题&#xff0c;就遍历删除没啥特点&#xff0c; 83甚至不需要考虑第一个结点的特殊情况&#xff0c;属实是名副其实的easy了 LeetCode&#xff1a;21.合并两个有序链表之第一次的特殊情况-CSDN博客 83. 删除排序链表中的重复元素 - 力扣&#xff08;Lee…

controller-manager学习三部曲之三:deployment的controller启动分析

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 《controller-manager学习三部曲》完整链接 通过脚本文件寻找程序入口源码学习deployment的controller启动分析 本篇概览 本文是《controller-manager学习三…

【C++初阶】第三站:类和对象(中) -- 类的6个默认成员函数

目录 前言 类的6个默认成员函数 构造函数 概念 特性 析构函数 概念 特性 拷贝构造函数 概念 特征 赋值运算符重载 运算符重载 赋值运算符重载 const成员 const修饰类成员函数 取地址及const取地址操作符重载 本章总结&#xff1a; 前言 有时候我们写好了一个栈&#xff0c;头脑…

C#中implicit和explicit

理解: 使用等号代替构造函数调用的效果以类似重载操作符的形式定义用于类型转换的函数前者类型转换时候直接写等号赋值语法,后者要额外加目标类型的强制转换stirng str -> object o -> int a 可以 int a (int)(str as object)转换通过编译,但没有转换逻辑所以运行会报错…

《UE5_C++多人TPS完整教程》学习笔记14 ——《P15 创建我们自己的子系统(Creating Our Own Subsystem)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P15 创建我们自己的子系统&#xff08;Creating Our Own Subsystem&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&…

G85银昆高速宝鸡天台山隧道群荣获交通运输部科技示范工程,北京恒星科通隧道无线通信与广播系统应用于该项目

2023年9月12日&#xff0c;全国交通运输科技示范工程现场推进会在河南省平顶山市召开&#xff0c;会上为全国已通过验收的10项科技示范工程进行了授牌&#xff0c;其中由陕西交控集团负责实施的“秦岭天台山超长隧道群安全绿色科技示范工程”名列其中。 【授牌仪式现场】 据了解…

我让ChatGPT帮我钓妹子,它一口气撩了5000人

来自俄罗斯的一名AI开发者、社交平台TenChat的产品经理 AleksandrZhadan于1月30日在推特上发布了自己的婚讯&#xff0c;他将要与自己的女友Karina Imranovna在今年的8月结婚。令人震惊的是Aleksandr Zhadan介绍的认识女友的窍门-ChatGPT 帮他找到了另一半&#xff0c;并且通过…

vue-进阶语法(四)

目录 v-model原理 v-model应用于组件 sync修饰符 ref 和 $refs&#xff08;重点&#xff09; $nextTick v-model原理 原理&#xff1a;v-model本质上是一个语法糖。例如应用在输入框上&#xff0c;就是 value属性 和 input事件 的合写。 作用&#xff1a;提供数据的双向…

测试西门子博途S7-PLCSIM Advanced V5.0的使用

原创 honeytree 西门子博途S7-PLCSIM Advanced V5.0能支持S7-1500&#xff0c;S7-1500R/H&#xff0c;ET200SP&#xff0c;ET200pro的仿真&#xff0c;用此仿真器可以模拟实际的PLC&#xff0c;用于其他软件的连接&#xff0c;比如上位机软件、触摸屏软件,自己用高级语音开发…

VUE学习之路——列表渲染

<p v-for"item in items">{{ item }}</p>使用v-for进行列表的渲染。 这仅仅是一个简单的demo&#xff0c;使用v-for可以用来遍历数组和对象&#xff0c;具体如下&#xff1a; 注意&#xff1a;遍历数组或对象的时候&#xff0c;&#xff08;&#xff09;…

java客运管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java客运管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&#…

几个好用的 iphone 手机模板贴图样机

整理了几个好用的 iphone 手机模板贴图&#xff0c;分享一下。 关注订阅号「设计师工作日常」&#xff0c;发送关键词 iphone mockup ,获取下载链接。 [1] 原文阅读 我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;求点赞求关注&#xff01;

问题:3【单选题】实现职业理想的一般步骤是()。 #媒体#媒体

问题&#xff1a;3【单选题】实现职业理想的一般步骤是()。 A、创业-立业-择业 B、择业-创业-立业 C、择业-立业-创业 D、立业-择业-创业 参考答案如图所示

Git分支和迭代流程

Git分支 feature分支&#xff1a;功能分支 dev分支&#xff1a;开发分支 test分支&#xff1a;测试分支 master分支&#xff1a;生产环境分支 hotfix分支&#xff1a;bug修复分支。从master拉取&#xff0c;修复并测试完成merge回master和dev。 某些团队可能还会有 reale…

分享76个行业PPT,总有一款适合您

分享76个行业PPT&#xff0c;总有一款适合您 76个行业PPT下载链接&#xff1a;https://pan.baidu.com/s/17zUV16XOg9uBfDTH7sURxw?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知…

有趣儿的组件(HTML/CSS)

分享几个炫酷的组件&#xff0c;起飞~~ 评论区留爪&#xff0c;继续分享哦~ 文章目录 1. 按钮2. 输入3. 工具提示4. 单选按钮5. 加载中 1. 按钮 HTML&#xff1a; <button id"btn">Button</button>CSS&#xff1a; button {padding: 10px 20px;text-tr…

怎么使用ChatGPT提高工作效率?

怎么使用ChatGPT提高工作效率&#xff0c;这是一个有趣的话题。 相信不同的人有不同的观点&#xff0c;大家的知识背景和从事的工作都不完全相同&#xff0c;所以最终ChatGPT能起到的作用也不一样。 在编程过程中&#xff0c;如果我们要找一个库&#xff0c;我们最先做的肯定…

解决MAC连上wifi或热点却不能上网问题

解决MAC连上wifi或热点却不能上网问题 #新换的mac昨天还能连上wifi&#xff0c;今天就不好使了。 找到连接的wifi点击详细信息&#xff0c;选择TCP/IP 中的配置IPV4 选择关闭
最新文章