linux——信号

✅<1>主页::我的代码爱吃辣
📃<2>知识讲解:Linux——进程等待
☂️<3>开发环境:Centos7
💬<4>前言:生活中处处有信号,linux中也有很多信号,OS使用来通知进程,控制进程,更好的管理进程。

目录

一.生活中的信号

二.技术应用角度的信号

三.信号的捕捉

 四.信号的产生

 1. 通过终端按键产生信号

 2. 调用系统函数向进程发信号

3.由软件条件产生信号

 4. 硬件异常产生信号

 五.核心转储


一.生活中的信号

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

二.技术应用角度的信号

  1. 用户输入命令,在Shell下启动一个前台进程。
  2. 用户按下 Ctrl-C ,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程。
  3. 前台进程因为收到信号,进而引起进程退出。

 测试代码:

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

测试结果:

 注意:

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

查看信号列表:

kill -l 

  1. Ctrl + C 就是给前台进程发送 2号信号 SIGINT。
  2. 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定 义 #define SIGINT 2。
  3. 编号34以上的是实时信号,本章只讨论编号34以下的信号,不讨论实时信号。
  4. 这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明: man 7 signal。

三.信号的捕捉

当我们按下Ctrl + C 前台进程会收到 2 号信号。那我们如何验证进程收到了2号信号呢?

 介绍一个系统调用:

头文件: #include <signal.h>

typedef void (*sighandler_t)(int);

接口定义:sighandler_t signal(int signum, sighandler_t handler)。

作用:捕捉信号signnum,将signum的默认动作修改为 hander。

参数:1.signum信号编号   2.handler回调的方法。

测试代码:

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <signal.h>using namespace std;void handle(int signum)
{cout << "I get a signal:" << signum << endl;
}int main()
{signal(2, handle);while (1){printf("I am a process, I am waiting signal!\n");sleep(1);}
}

测试结果:

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

在上述的代码中2号信号的默认动作是终止进程,当我们对2好信号进行捕捉,并且将2号信号的默认动作修改为我们自定义的一个函数。因此我们再次Ctrl + C,进程收到2号信号就不会终止,而是执行我们设计的函数。我们继续可以使用Ctrl + \ 终止进程。

 四.信号的产生

 1. 通过终端按键产生信号

 中断按键,就是我们的键盘,当我们按下Ctrl + C 时OS会向前台进程发送2号信号。还有Ctrl + \ 可以向前台进程发送。

 2. 调用系统函数向进程发信号

#include <signal.h>

#include <sys/types.h>

int kill(pid_t pid, int signo);向指定进程发指定信号。
int raise(int signo);向调用进程发送指定信号。
这两个函数都是成功返回0,错误返回-1。

#include <stdlib.h>
void abort(void);
就像exit函数一样,abort函数总是会成功的,所以没有返回值,给进程发送6号信号,6号直接终止进程。

kill-测试代码:

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>using namespace std;void handle(int signum)
{cout << "I am child process,my PID :" << getpid() << ",I get a signal:" << signum << endl;// 进程退出exit(0);
}int main()
{// 创建子进程pid_t pid = fork();if (pid == 0){// 让子进程捕捉2号信号signal(2, handle);while (1){printf("I am child process, my PID :%d,I am waiting signal!\n", getpid());sleep(1);}}int count = 5;while (count){printf("%d秒之后我将给%d号进程发2号信号\n", count--, pid);sleep(1);}// 给子进程发送2号信号kill(pid, 2);sleep(1);return 0;
}

测试结果:

 raise-测试代码

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>using namespace std;void handle(int signum)
{cout << "I am process,I get a signal:" << signum << endl;// 进程退出exit(0);
}int main()
{// 让进程捕捉2号信号signal(2, handle);int count = 5;while (count){printf("%d秒之后我将给自己发2号信号\n", count--);sleep(1);}// 给子进程发送2号信号raise(2);sleep(1);return 0;
}

测试结果:

abort-测试代码:

 代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>using namespace std;void handle(int signum)
{cout << "I am process,I get a signal:" << signum << endl;// 进程退出exit(0);
}int main()
{// 让进程捕捉6号信号signal(6, handle);int count = 5;while (count){printf("%d秒之后我将给自己发6号信号\n", count--);sleep(1);}// 给子进程发送6号信号abort();sleep(1);return 0;
}

测试结果:

3.由软件条件产生信号

 SIGPIPE是一种由软件条件产生的信号,在“管道”中已经介绍过了。

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

调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。

 测试代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>using namespace std;
int main()
{// 设置闹钟alarm(5);int count = 5;while (count){printf("%d秒之后闹钟响,进程终止\n", count--);sleep(1);}sleep(15);return 0;
}

测试结果:

 4. 硬件异常产生信号

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

除0异常模拟:

测试代码:

int main()
{cout << "begin" << endl;cout << "begin" << endl;int num = 10;int tmp = num / 0;cout << "end" << endl;cout << "end" << endl;return 0;
}

 说明:在运行到除0的地方,进程直接终止了,原因是进程收到了8号信号。

野指针异常模拟:

测试代码:

int main()
{cout << "begin" << endl;cout << "begin" << endl;int *point = nullptr;*point = 100;cout << "end" << endl;cout << "end" << endl;return 0;
}

测试结果:

由此可以确认,我们在C/C++当中除零,内存越界等异常,在系统层面上,是被当成信号处理的。

 总结:

  • 上面所说的所有信号产生,最终都要有OS来进行执行,为什么?OS是进程的管理者。
  • 信号的处理是否是立即处理的?在合适的时候。
  • 信号如果不是被立即处理,那么信号是否需要暂时被进程记录下来?记录在哪里最合适呢?进程PCB中。
  • 一个进程在没有收到信号的时候,能不能知道,自己应该对合法信号作何处理呢?知道。
     

 五.核心转储

我们在进程控制时,讲到进程等待,我们与遇到过这个概念:

首先解释什么是核心转储(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

  1. SIGINT信号Action是Term,代表直接退出不进行多余的动作
  2. SIGQUIT信号Action是Core,代表退出前进行核心转储。

 使用命令$:ulimit -a 可以查看进程的资源分配信息,其中也包括core 文件大小。

 使用命令:ulimit -c 10240,给core dump添加大小。

 测试代码:

int main()
{pid_t pid = fork();if (pid == 0){cout << "begin" << endl;cout << "begin" << endl;int *point = nullptr;*point = 100;cout << "end" << endl;cout << "end" << endl;}int status = 0;waitpid(pid, &status, 0);cout << "core dump:" << ((status >> 7) & 1) << endl;cout << "signal:" << (status & 0x3f) << endl;return 0;
}

 测试结果:

 说明:

  • 当我们放开核心转储以后,之后执行的程序一旦收到core信号,就会在当前目录下生成一个core.XXX核心转储文件。
  • 这个文件是一个二进制文件。
  • 可以使用gdb对debug可执行程序进行调试,然后使用core-file core.XXX查看核心转储信息。

查看核心转储文件:

  1. 使用debug编译文件。
  2. 使用gdb调试可执行程序。
  3. 在gdb中使用core-file产看core.XXX文件按

 

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Elasticsearch安装并使用Postman访问

Elasticsearch&#xff0c;一个强大的开源搜索和分析引擎&#xff0c;已经在全球范围内被广泛应用于各种场景&#xff0c;包括网站搜索、日志分析、实时应用等。由于其强大的功能和灵活性&#xff0c;Elasticsearch 已经成为大数据处理的重要工具。然而&#xff0c;对于许多初次…

设计模式11、享元模式Flyweight

解释说明&#xff1a;享元模式&#xff08;Flyweight Pattern&#xff09;运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象&#xff0c;而这些对象都很相似&#xff0c;状态变化很小&#xff0c;可以实现对象的多次复用。 抽象享元类&#xff08;Flyweight&…

【记录】IDA|IDA怎么查看当前二进制文件自动分析出来的内存分布情况(内存范围和读写性)

IDA版本&#xff1a;7.6 背景&#xff1a;我之前一直是直接看Text View里面的地址的首尾地址来判断内存分布情况的&#xff0c;似乎是有点不准确&#xff0c;然后才想到IDA肯定自带查看内存分布情况的功能&#xff0c;而且很简单。 可以通过View-Toolbars-Segments&#xff0c…

竞赛选题 机器视觉人体跌倒检测系统 - opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 机器视觉人体跌倒检测系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&…

Kafka日志索引详解以及生产常见问题分析与总结

文章目录 1、Kafka的Log日志梳理1.1、Topic下的消息是如何存储的&#xff1f;1.1.1、 log文件追加记录所有消息1.1.2、 index和timeindex加速读取log消息日志。 1.2、文件清理机制1.2.1、如何判断哪些日志文件过期了1.2.2、过期的日志文件如何处理 1.3、Kafka的文件高效读写机制…

MySQL-MVCC(Multi-Version Concurrency Control)

MySQL-MVCC&#xff08;Multi-Version Concurrency Control&#xff09; MVCC&#xff08;多版本并发控制&#xff09;&#xff1a;为了解决数据库并发读写和数据一致性的问题&#xff0c;是一种思想&#xff0c;可以有多种实现方式。 核心思想&#xff1a;写入时创建行的新版…

【多任务案例:猫狗脸部定位与分类】

【猫狗脸部定位与识别】 1 引言2 损失函数3 The Oxford-IIIT Pet Dataset数据集4 数据预处理4 创建模型输入5 自定义数据集加载方式6 显示一批次数据7 创建定位模型8 模型训练9 绘制损失曲线10 模型保存与预测 1 引言 猫狗脸部定位与识别分为定位和识别&#xff0c;即定位猫狗…

MacOS怎么安装Nacos(附带:Windows系统)

MacOS安装Nacos&#xff08;一定要配置JDK的环境变量&#xff0c;后面告诉你为什么&#xff1f;&#xff09; &#xff08;1&#xff09;进入Nacos官网&#xff0c;前往githubhomehomehttp://nacos.io/zh-cn/ &#xff08;2&#xff09;点击右下角的releases 然后点击Tags 选择…

代码随想录算法训练营第五十七天 | 392.判断子序列 115.不同的子序列

1. 判断子序列 392. 判断子序列 - 力扣&#xff08;LeetCode&#xff09; dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c;和以下标j-1为结尾的字符串t&#xff0c;相同子序列的长度。 class Solution {public boolean isSubsequence(String s, String t) {//dp[i][j] 表示…

Redis7的数据结构

Redis以键-值对的形式存储数据 一、键 1、键的特点 键是一个字符串&#xff0c;这个字符串的内容可以是数字、字符序列&#xff0c;也可以是一个文件的字节序列&#xff0c;甚至空字符串也可以做为key。 在一个数据库中键必须是唯一的。 键最大可以达到512M&#xff0c;但太…

通用收藏管理器Koillection

什么是 Koillection &#xff1f; Koillection 是一个自托管的收藏管理器&#xff0c;旨在跟踪任何类型的物理&#xff08;主要&#xff09;收藏&#xff0c;如书籍、DVD、邮票、游戏……&#xff0c;由于 Koillection 旨在用于任何类型的收藏&#xff0c;它不支持自动下载元数…

STM32 DMA从存储器发送数据到串口

1.任务描述 &#xff08;1&#xff09;ds18b20测量环境温度存储到存储器&#xff08;数组&#xff09;中。 &#xff08;2&#xff09;开启DMA将数组中的内容&#xff0c;通过DMA发送到串口 存在问题&#xff0c;ds18b20读到的数据是正常的&#xff0c;但是串口只是发送其低…

Redis最常见的5种应用场景

Redis作为当今最流行的内存数据库&#xff0c;已经成为服务端加速的必备工具之一。对于Redis为什么那么快&#xff1f;以及Redis采用单线程&#xff0c;但为什么反而获得更高的性能的疑问&#xff0c;在之前的Redis为什么那么快&#xff1f;一文中&#xff0c;已经有所介绍。 …

全新UI彩虹外链网盘系统源码(前后端美化模板)

全新UI彩虹外链网盘系统源码前后端美化模板&#xff0c;支持所有格式文件的上传、生成文件外链、图片外链、音乐视频外链等功能&#xff0c;同时还可以自动生成相应的 UBB 代码和 HTML 代码&#xff0c;支持文本、图片、音乐、视频在线预览。这不仅仅是一个网盘&#xff0c;更是…

证书显示未受信任,生成的证书过期

此时若是导入证书后&#xff0c;证书显示未受信任&#xff0c;则说明我们缺失最新的AppleWWDRCA证书 解决方案&#xff1a; 重新下载AppleWWDRCA并安装。即下载最新的AppleWWDRCA证书&#xff0c;双击安装到“登录”项的钥匙串下&#xff1b;然后再安装你的开发证书或者发布证书…

WebSocket实战之六心跳重连机制

一、前言 WebSocket应用部署到生产环境&#xff0c;我们除了会碰到因为经过代理服务器无法连接的问题&#xff08;注&#xff1a;该问题可以通过搭建WSS来解决&#xff0c;具体配置请看 WebSocket实战之四WSS配置 &#xff09;&#xff0c;另外一个问题就是外网环境不稳定经常…

Appium开发

特点 开源免费支持多个平台 IOS(苹果)、安卓App的自动化都支持 支持多种类型的自动化 支持苹果、安卓应用原生界面的自动化支持应用内嵌网络视图的自动化支持手机浏览器(Chrome)中的web网站自动化支持flutter应用的自动化 支持多种编程语言 像selenium一样&#xff0c;可以用多…

react.js在visual code 下的hello World

想学习reacr.js &#xff0c;就开始做一个hello world。 我的环境是visual code &#xff0c;所以我找这个环境下的例子。参照&#xff1a; https://code.visualstudio.com/docs/nodejs/reactjs-tutorial 要学习react.js &#xff0c;还得先安装node.js&#xff0c;我在visual …

面试打底稿④ 专业技能的第四部分

简历原文 抽查部分 了解Python的使用&#xff08;第一篇关于Python升级版本bug解决的文章斩获6W阅读&#xff09;&#xff0c;用python实现了几篇图像信息隐藏领 域论文的复现&#xff08;博客中有提及&#xff09;&#xff1b; 了解Django基本框架&#xff0c;写过Django框架的…

【软考】4.2 关系代数

《 关系代数 》 表和表之间的逻辑运算 笛卡尔积&#xff1a;S1 x S2 投影&#xff1a;π&#xff1b;选择某一列&#xff08;属性&#xff09;&#xff1b;一个关系R的投影操作结果也是一个关系&#xff0c;记作Πa&#xff0c;它由从关系R中选出的A列元素构成&#xff1b;选择…