【Linux系统化学习】信号概念和信号的产生

2024-02-29 03:04

本文主要是介绍【Linux系统化学习】信号概念和信号的产生,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

信号的概念

从生活中的例子中感知信号

前台进程和后台进程

前台进程

后台进程

操作系统如何知道用户向键盘写入数据了?

进程如何得知自己收到了信号?

信号捕捉

signal函数

Core Dump(核心转储)

信号产生的方式

通过键盘按键产生信号

kill函数

raise函数

硬件异常产生信号

浮点数异常

非法地址异常 

由软件条件产生信号

alarm函数


信号的概念

从生活中的例子中感知信号

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

通过上面的例子我们可以总结出来一下四点:

  • 信号没有产生的时候,其实我们已经直到怎么处理这个信号了。
  • 信号的到来我们并不清楚具体什么时候,信号的到来对于我正在做的工作是异步产生的。
  • 信号产生了,我们不一定要立即处理它,而是我们在合适的时候处理。
  • 我们有一种能力,可以将已经到来的信号进行暂时保存。

让我们转换视角,将我们看成操作系统中被操作系统管理的进程;在进程运行期间根本不知道操作系统什么时候会给这个进程传递一种信息,当操作系统的信息来临时进程可以选择直接处理这个信息,也可以将信息暂时保存下来。

到此我们可以给信号下个定义信号是一种向目标进程发送通知消息的一种机制

在了解信号的产生之前我们还需要一点预备知识让我们对操作系统的信号机制了解的更全面一点。


前台进程和后台进程

前台进程

当我们循环执行一条输出语句时,执行我们的Linux指令操作系统是没有任何相应的;也就是操作系统没有能力接受用户的输入

后台进程

只需要在运行可执行程序时指令的后面添加一个按位与的位运算符即可成为后台进程。后台进程有能力可以接受用户的输入,当我么输入指令后shell会执行我们的命令。

查看后台进程:

jobs

将后台进程调整为前台进程:

fg number(后台每个进程的任务号)

将前台进程调整为后台进程

ctrl + z
//先对前台进程进行暂停
bg number
//然后在进行调整

总结: 

  1. 前台进程有且只有一个,一般情况下为shell。
  2. 操作系统会自动将shell提到前台或者后台。
  3. 前台进程可以被ctrl+c终止掉。
  4. 前台进程不可以被暂停,如果被暂停该前台进程必须被放到后台。 

操作系统如何知道用户向键盘写入数据了?

操作系统是管理者,键盘、显示器、网卡等这些硬件也是要被操作系统管理起来的。当我们使用键盘进行写入操作时,键盘文件会发生变化;操作系统会将这些输入的数据进行各种处理。但是根据冯诺依曼体系结构外设是不可以和CPU进行打交道的,可以通过其他硬件间接联系。CPU中含有很多针脚,外设通过8259主板和CPU上的针脚关联。每个针脚对应一个外设,当我们键盘进行写入时,高低电平会通过主板让针脚发生“变化”。这样CPU就可以知道键盘进行写入了然后读取数据,对数据进行处理。这样的方式称作中断,引起中断的原因称作中断源。对于CPU上的针脚,操作系统也是需要进行管理的,使用一个函数指针数组;数组中的指针指向该针脚对应外设的读写操作函数。这个函数指针数组被称为断向量表。

因此信号的本质就是使用软件来模拟中断的行为。


进程如何得知自己收到了信号?

前面的文章中我们简单提到过信号系统中总共含有62中信号;其中 1-31为普通信号,34-64为实时信号,且没有0号信号。这篇文章我们只探讨普通信号,不对实时信号做任何解释和介绍。

可以使用kill -l查看系统信号

每个信号都含有一个数字编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定 义 #define SIGINT 2。

前面的文章我们介绍了每个进程都会被操作系统管理起来,形成一个结构体(PCB)其中含有进程的属性和信息;在这个结构体中就含有一个信号位图,每个比特位代表对应的信号每个比特位对应的内容表示是否收到了信号。当进程收到信号之后,会修改这个信号位图表示收到了某中信号。


信号捕捉

上面提到每个信号都有编号和宏定义,当进程收到某种信号时会调用系统默认的方法;Linux操作系统支持我们使用函数将默认方法改写。

signal函数

//头文件
#include<signal.h>
//函数名称
signal(signo,(void)(*)(int))
  • 第一个参数表示我们要对哪个信号进行捕捉。
  • 第二个参数是一个参数为整形的函数指针,指向我们重写的函数;这个函数的参数也为我们的第一个参数。

注意:对于9号进程来说是不可以被重写函数的。


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 -c 1024。

#include<iostream>
using namespace std;
int main()
{int a=10;a/=0;return 0;
}

使用指令修改限制,允许产生core文件;专门制造一个浮点数异常编译并运行后会产生一个和本进程id相关的core文件;我们可以发现这个文件是非常大的,程序运行时如果出现这类异常会将我们的磁盘写满,造成无法进行修改这也是为什么系统默认不允许产生core文件。


信号产生的方式

通过键盘按键产生信号

通过键盘进行信号的产生就像我们上面使用键盘输入crtl +c可以终止一个进程,当这个键盘输入组合键时会产生一个硬件中断,被操作系统获取,解释成为2号信号,发送给目标前台进程。进程会修改自己PCB中的信号位图,表示已经收到信号。

前台进程因为接收到引号,直接对信号进行处理,进而终止进程。

此外常用的组合键含有:ctrl + z 默认暂停进程 ctrl + \ 默认退出进程

通过系统调用/指令产生信号

kill函数

//头文件
#include<sys/types.h>
#include<signal.h>
//函数
int kill(pid_t pid, int sig)

参数说明:

  • pid:表示进程的pid,代表向哪一个进程发送。
  • sig:表示发送信号的编号。 
#include<iostream>2 #include<unistd.h>3 #include<signal.h>4 #include<sys/types.h>                                              5 using namespace std;                                                  10 int main()                           11 {                                    12     cout<<"wait 2 signal"<<endl;     13     sleep(2);                        14     kill(getpid(),9);                15     cout<<"WTF"<<endl; return 0;}

上面的代码演示了使用kill函数给自身进程产生了9号信号,并由操作系统发送成功;也可以通过另一个进程给一个指定的进程发送指定的信号。

raise函数

//头文件
#include<signal.h>
//函数
int raise(int sig);

参数说明:

  • sig:代表信号编号。
  • raise专门用来给自己发送指定的信号的。 
 #include<iostream>2 #include<unistd.h>3 #include<signal.h>4 #include<sys/types.h>5 using namespace std;10 int main()11 {12     cout<<"wait signal"<<endl;13     raise(9);    reutrn 0;}                                                  

硬件异常产生信号

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

浮点数异常

#include<iostream>
using namespace std;
int main()
{int a=10;a/=0;return 0;
}

非法地址异常 

#include<iostream>
using namespace std;
int main()
{int* a=NULL;*a=100;return 0;
}

 

由软件条件产生信号

在之前管道的文章,匿名管道如果读端关闭,写端一直写入;操作系统就会发送SIGPIPE(13)号信号终止目标进程。SIGPIPE就是一种由软件条件产生的信号。

alarm函数

//头文件
#include <unistd.h>
//函数
unsigned int alarm(unsigned int seconds);

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

这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。打个比方,某人要小睡一觉,设定闹钟为30分钟之后响,20分钟后被人吵醒了,还想多睡一会儿,于是重新设定闹钟为15分钟之后响,“以前设定的闹钟时间还余下的时间”就是10分钟。如果seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数。

#include<iostream>
#include<unistd.h>
int cnt = 0;
int main()
{alarm(1);while(true){cnt++;cout<<cnt<<endl;}return 0;
}


今天对Linux下信号的产生的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!!  

这篇关于【Linux系统化学习】信号概念和信号的产生的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/757384

相关文章

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用

Linux Mint Xia 22.1重磅发布: 重要更新一览

《LinuxMintXia22.1重磅发布:重要更新一览》Beta版LinuxMint“Xia”22.1发布,新版本基于Ubuntu24.04,内核版本为Linux6.8,这... linux Mint 22.1「Xia」正式发布啦!这次更新带来了诸多优化和改进,进一步巩固了 Mint 在 Linux 桌面

LinuxMint怎么安装? Linux Mint22下载安装图文教程

《LinuxMint怎么安装?LinuxMint22下载安装图文教程》LinuxMint22发布以后,有很多新功能,很多朋友想要下载并安装,该怎么操作呢?下面我们就来看看详细安装指南... linux Mint 是一款基于 Ubuntu 的流行发行版,凭借其现代、精致、易于使用的特性,深受小伙伴们所喜爱。对

什么是 Linux Mint? 适合初学者体验的桌面操作系统

《什么是LinuxMint?适合初学者体验的桌面操作系统》今天带你全面了解LinuxMint,包括它的历史、功能、版本以及独特亮点,话不多说,马上开始吧... linux Mint 是一款基于 Ubuntu 和 Debian 的知名发行版,它的用户体验非常友好,深受广大 Linux 爱好者和日常用户的青睐,

Linux(Centos7)安装Mysql/Redis/MinIO方式

《Linux(Centos7)安装Mysql/Redis/MinIO方式》文章总结:介绍了如何安装MySQL和Redis,以及如何配置它们为开机自启,还详细讲解了如何安装MinIO,包括配置Syste... 目录安装mysql安装Redis安装MinIO总结安装Mysql安装Redis搜索Red

Linux中Curl参数详解实践应用

《Linux中Curl参数详解实践应用》在现代网络开发和运维工作中,curl命令是一个不可或缺的工具,它是一个利用URL语法在命令行下工作的文件传输工具,支持多种协议,如HTTP、HTTPS、FTP等... 目录引言一、基础请求参数1. -X 或 --request2. -d 或 --data3. -H 或

Linux磁盘分区、格式化和挂载方式

《Linux磁盘分区、格式化和挂载方式》本文详细介绍了Linux系统中磁盘分区、格式化和挂载的基本操作步骤和命令,包括MBR和GPT分区表的区别、fdisk和gdisk命令的使用、常见的文件系统格式以... 目录一、磁盘分区表分类二、fdisk命令创建分区1、交互式的命令2、分区主分区3、创建扩展分区,然后

Linux中chmod权限设置方式

《Linux中chmod权限设置方式》本文介绍了Linux系统中文件和目录权限的设置方法,包括chmod、chown和chgrp命令的使用,以及权限模式和符号模式的详细说明,通过这些命令,用户可以灵活... 目录设置基本权限命令:chmod1、权限介绍2、chmod命令常见用法和示例3、文件权限详解4、ch

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

Linux使用nohup命令在后台运行脚本

《Linux使用nohup命令在后台运行脚本》在Linux或类Unix系统中,后台运行脚本是一项非常实用的技能,尤其适用于需要长时间运行的任务或服务,本文我们来看看如何使用nohup命令在后台... 目录nohup 命令简介基本用法输出重定向& 符号的作用后台进程的特点注意事项实际应用场景长时间运行的任务服