目录
1.信号
1.1.知识引入
生活中我们常常都在接收着信号,信号产生时到信号对应的事件被我们处理,可以存在一段时间差,也就是信号产生和处理是支持异步的。怎么理解这一句话呢?
我们正在处理一个程序的bug时,外卖小哥打电话给你说你的外卖到了,这时我们接收到“外卖到了”这一个信号,那么我们有两个选择,直接下去拿或者让他放在外卖柜等你解决了这个bug你再去拿这两种行为,对于后者就形成了“异步”,而外卖小哥放完外卖就可以离开了。
这里对应着:信号产生了,我们不一定要立即处理,我们可以选择合适的时机处理。但前提是我们需要有暂时保存信号的能力,和能够知道如何处理这个信号,信号的产生是异步的。
信号处理的常见方式:
- 忽略此信号。
- 执行该信号的默认处理动作。
- 自定义自己的处理方式
那什么是信号呢?
信号是一种向目标进程发送通知信息的一种机制,也称为进程之间事件异步通知的一种方式,属于软中断。
【OS学习笔记】十一 实模式:中断-软中断和硬中断基本原理_实模式中断-优快云博客
这里转载了一篇关于软件中断和硬件中断的博客,在信号篇章中我们主要讲一下软中断的现象……
同步和异步:
同步操作:在发出一个调用后,调用者会等待这个调用返回结果后,再继续执行后续的代码。同步操作要求调用者和被调用者之间保持一种紧密的协调,调用者必须等待被调用者完成操作后才能继续执行。这种等待可能导致调用者的线程或进程被阻塞,直到结果返回
我们在之前学习过管道通信,这种通信方式就是同步的,当数据没有被写入时,当读端在读取信息之前,一定要等待写端写入数据,才能进行读取。
异步操作:调用者在发出调用后,不必等待被调用者完成操作,即可继续执行后续的代码。被调用者在完成操作后,会通过某种机制(如回调函数、事件、Promise等)通知调用者。异步操作使得调用者能够在等待期间执行其他任务,从而提高了程序的并发性和效率。
而共享内存通信、消息队列我们就不需要进行强制等待,只要我们需要接收,随时都可以接收,这样的数据传输就是异步的。
1.2.信号的产生
产生信号的方式多种多样,但是给直接进程发信号的只有操作系统!!!
如图:为Linux内置的信号集合,通过kill -l查看系统中的信号列表,本质为宏替换
- 信号1-31称为普通信号,34-64称为实时信号
- 每一个进程都有一张自己的函数指针数组,数组的下标和信号编号强相关
而这个强相关的函数指针数组,提供给接收到信号的进程,在处于合适的时机调用对应信号操作的函数方法,来实现对信号的响应。
我们知道当进程接收到信号时,可以存在时间差来进行信号的处理,那么这就需要进程对收到的信号进行存储并且如何表示是否收到了某种信号?这时我们就很顺畅的想到了位图!
struct task_struct
{
// 信号位图
uint32_t signmap;
}
进程中维护一个位图,通过一个int整型32个比特位,比特位的位置来对应信号编号,比特位的01表示是否收到信号,而信号的产生就是操作系统向进程中发送(写)信号,即操作系统对进程的task_struct的位图对应位置由0置1的操作。
无论通过什么方式产生的信号,本质上都是与操作系统进行交互后,操作系统对进程进行信号的写入,而完成信号的写入后,就是通过下标索引调用对应的函数指针数组中的函数。
接下来我们就学习一下,常见的信号产生方式 ……
1.2.1.通过键盘产生信号
我们在讲解什么是信号时,提到了信号是一种软中断,这句话的意思是:信号的本质是用软件来模拟、实现中断的行为。在我们运行程序时,我们可以通过Ctrl + C来终止一个进程,也可以通过kill指令来终止,本质我们向键盘中输入指令,操作系统通过软硬件结合来向shell发送信号,当shell接收到这个信号后会将这个进程给关闭。
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include<stdlib.h>
using namespace std;
// 自定义一个信号处理的方式
void handler(int signal_id)
{
cout << "调用该命令时产生了一个:" << signal_id << " 信号" << endl;
exit(1);
}
int main()
{
// 向signal函数中 传入系统中定义的信号名、自定义的处理方式
signal(2, handl