操作系统:信号究竟是什么?如何产生?

OS信号

  • 一、信号的概念
  • 二、信号的产生
  • 1)终端按键产生信号
    • 1、 前台进程、后台进程
    • 2、验证终端按键是否产生信号
  • 2)调用系统函数向进程发信号
  • 3)硬件异常产生信号
    • 1、浮点数溢出,CPU产生信号
    • 2 浮点数溢出,产生信号原理
    • 3. 空指针解引用错误,MMU产生信号原理
  • 4)软件异常产生信号

一、信号的概念

信号是一种向目标进程发送信息,异步通知的一种方式,属于软中断。本质上是用软件来模拟中断行为!

 在生活中存在很多信号,诸如红绿灯、闹钟铃声、古代狼烟、防空警报等等。以红绿灯为例,我们是如何认识红绿灯信号的。根本原因在于我们在小时候就已经有人提前告诉你如何去识别它、对应的灯亮了意味这什么,要做什么!

 同理,在操作系统中已经提前内置了信号信息。我们通过kill -l查看:

在这里插入图片描述

  • 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到。其中 1~31为普通信号,43~64为实时信号(不关心),没有32、33号信号!这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明: man 7 signal

 在操作系统中,信号还没有产生之前,进程就能识别它(数字代号或宏),如何处理。信号的到来,我们并不清楚是什么时候,所以信号相对进程来说是异步的。信号产生后,进程不一定立即处理它,而是在合适的时候进程处理。所以我们需要将已经到来的信号进行保存

  • 所以信号如何产生?操作系统如何保存信息?

二、信号的产生

 在操作系统中,产生信号有4种方式:终端按键产生、系统调用产生、硬件异常产生、软件条件产生!

1)终端按键产生信号

 下面通过终端按键向前台进程和后台进程发送信号为例!

1、 前台进程、后台进程

 下面我们创建一个process.cc源文件,让其死循环输出信息。

#include <iostream>
#include <unistd.h>

int main()
{
    int cnt = 0;
    while(true)
    {
        std::cout << "running ..." << ++cnt << std::endl;
        sleep(1);
    }
    return 0;
}
  1. 我们编译运行后,产生一个前台进程。我们可以在终端输入ctrl c发送2号信号来终止前台进程!

请添加图片描述
 我们在键盘上按下ctrl z后,会产生硬件中断。操作系统会识别到硬件数据就绪,此时操作系统读键盘上的数据,发送给目标进程。前台进程因为收到2号信号,进而引起信号退出!!

  1. 我们也可以通过ctrl z发送20号信号暂停前台进程!但由于前台进程不能被暂停,否则键盘将失效。此时当前被暂停的前台进程后转化为后台进程。shell外壳进程快速从后台切换为前台进程。

 下面我们将前台进程输入重定向到log.txt,死循环打印消息。然后ctrl z发送20号信号,此时前台进程会变为后台进程。具体效果如下:

请添加图片描述

 我们发现ctrl z向目标进程发送20号信号后,前台进程变为后台进程,并且被暂停!

  1. jobs指令可以查看当前系统中的后台进程。
  2. bg 指令+ 后台进程编号可以重新启动后台进程。fg 指令+ 后台进程编号可以将后台进程提到前台,变为前台进程!
  3. 前台进程只能有一个(键盘只有一个),后台进程可以有多个。两者本质区别在于前台进程可以接收用户输入,后台不行。shell进程比较特殊,不会被ctrl c杀掉。并且根据具体情况,Os会自动将shell提到前台或后台!!

2、验证终端按键是否产生信号

 上述我们通过终端按键让进程产生一系列行为。当ctrl c真的向目标进程发送了2号信号吗?ctrl z真的向目标进程发送了20号信号吗?我们需要进一步验证!

 操作系统提供了一个signal系统调用即可,可以自定义捕捉信号。

 #include <signal.h>
 
 //函数原型如下,signal()第二个参数用于自定义捕捉信号
 typedef void (*sighandler_t)(int);
 sighandler_t signal(int signum, sighandler_t handler);

下面我们以自定义捕捉2号信号,分别通过终端ctrl c和用户主动发送2号信号,对比进程行为!!

【源代码如下】:自定义捕捉2号信号,让进程受到2号信号退出时,打印一段消息!!

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

void handler(int signo)
{
    std::cout << "自定义捕捉信号: " << signo << std::endl;
    exit(0);
}

int main()
{
    std::cout << "pid: " << getpid() << std::endl;
    //自定义捕捉2号信号,signal()会将待捕捉信号种类数字传给handler()
    signal(2, handler);
    int cnt = 0;
    while(true)
    {
        std::cout << "running ..." << ++cnt << std::endl;
        sleep(1);
    }
    return 0;
}

【终端ctrl c效果】:

请添加图片描述

【发送2号信号效果】:
请添加图片描述

  • 我们发现两者行为一直,系统都受到了2号信号。进一步验证终端输入可以发送信号!!

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

 操作系统提供了系统调用接口kill,用来向指定进程发送特定信号!

 //函数原型
 #include <sys/types.h>
 #include <signal.h>

 int kill(pid_t pid, int sig);
 //发送成功,返回0;否则返回-1

【实例】:进程打印3次消息后,通过系统调用接口发送2号信号

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

void handler(int signo)
{
    std::cout << "自定义捕捉信号: " << signo << std::endl;
    exit(0);
}

int main()
{
    int count = 3, cnt = 0;
    signal(2, handler);//自定义捕捉2号信号
    while(true)
    {
        std::cout << "running ..." << ++cnt << std::endl;
        if(--count == 0)
            kill(getpid(), 2);
        sleep(1);
    }
    return 0;
}

【运行结果】:
请添加图片描述

  1. kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。
  2. raise函数可以给当前进程发送指定的信号(自己给自己发信号)。
#include <signal.h>
int raise(int signo);
//是成功返回0,错误返回-1。
  1. abort函数使当前进程接收到信号而异常终止。
#include <stdlib.h>
void abort(void);
//就像exit函数一样,abort函数总是会成功的,所以没有返回值。

3)硬件异常产生信号

 下面以浮点数溢出和空指针解非法解引用错误为例

1、浮点数溢出,CPU产生信号

 我们知道除式中,除数为0是非法的。此时CUP硬件会发送8号信号,表示浮点数异常Floating point exception。我们先来看看相关现象,代码如下:(我们特意让进程一直被运行,并且8号信号自定义捕捉。进程收到8号信号时不退出

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

void handler(int signo)
{
    std::cout << "自定义捕捉信号: " << signo << std::endl;
    sleep(1);
}

int main()
{
    std::cout << "pid: " << getpid() << std::endl;
    signal(8, handler);

    int x = 10;
    x /= 0;
    while(true)
    {}
    return 0;
}

【运行结果】:

请添加图片描述
 我们观察到进程确实收到了8号信号。

2 浮点数溢出,产生信号原理

 在CPU中存在许多寄存器,其中存在一个名为status的状态寄存器,其中存在一个标志位用来保存最近一次运算结果是否发送溢出!!
 加上我们CPU寄存器eax中保存10,ebx寄存器中保存0。10/0,本质上是除一个无限小的数,导致结果无限大,发生溢出。此时操作系统会识别到该信息,然后立即将当前进程从CPU上剥离,添加到某种异常处理队列。

 此时操作系统会将该异常解释位kill(targetprocess, signo)。然后保存到进程PCB中!当异常处理完后,会被CPU再次调度运行,执行后续代码!

 但此时我们自定义捕捉了8号信号,没有让进程退出,会一直循环上述过程。
在这里插入图片描述

3. 空指针解引用错误,MMU产生信号原理

 MMU(内存管理单元),它是一种负责处理中央处理器(CPU)的内存访问请求的计算机硬件,现如今一般别集成到CPU上。 它的功能包括虚拟地址到物理地址的转换(即虚拟内存管理)、内存保护等!

 对空指针进行非法解引用,即试图对0号地址进行写入。但此时页表中没有建立相关映射,此时MMU进程虚拟地址向物理地址转化时发送失败,MMU报错,相关标志位改变。该变化会被OS识别后向目标进程写信号!!

4)软件异常产生信号

 对于管道,比如匿名管道等存在同步机制的管道。当读端关闭,此时管道写端也会关闭退出。这就是一种典型的软件异常。当管道写端关闭,写端进行写入时会触发 SIGPIPE14信号。进而关闭读端退出!

 下面我i们以alarm函数为例,测试软件异常。
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。

//函数原型
  #include <unistd.h>
  unsigned int alarm(unsigned int seconds);
//返回值是0或者是以前设定的闹钟时间还余下的秒数

 下面我们设置一个3秒的闹钟,程序运行后闹钟醒来发送14号信号!

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

int cnt = 0;

void handler(int signo)
{
	//下面注释代码:我们可以主动发送14号信号,历史闹钟剩余时间,并取消历史闹钟
    //int n = alarm(0);//取消历史闹钟,如果存在返回剩余时间
    //std::cout << "result:" << n << std::endl;
    
    std::cout << "自定义捕捉信号: " << signo << "alarm" << std::endl;
    exit(0);
}

int main()
{
    std::cout << "pid: " << getpid() << std::endl;
    signal(14, handler);
    alarm(30);

    while (true)
    {
        sleep(1);
    }
    return 0;
}

【运行结果】:
请添加图片描述

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

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

相关文章

字节码编程javassist之修改返回值

写在前面 本文看下如何修改返回值。 代码 需要增强的类&#xff1a; package com.dahuyou.javassist.huohuo.cc;import java.math.BigDecimal;public class MyApiTestNoAnnotation {public double queryUserInfo(String uId){return BigDecimal.ONE.doubleValue();}}插桩类…

JavaWeb—js(3)

Bom dom: document object model(文档对象模型), 是处理html、xml的标准编写接口。 节点和元素 整个页面也就是整个文档我们称之为文档节点; 文档节点使用document来表示; 页面中的所有标签我们称之为元素&#xff0c;使用element来表示; 如此处的文本、属性、注释等&…

腾讯又一平台即将停止运营

随着腾讯公司业务和战略的调整&#xff0c;某些业务逐渐退出历史舞台&#xff0c;如“腾讯直播平台NOW”&#xff0c;以及“QQ签到”&#xff0c;“腾讯待办”&#xff0c;“企鹅FM音频平台”等&#xff0c;最近又有一则重磅消息&#xff0c;那就是“腾讯课堂”也即将停止运营。…

前端构建工具(webpackvite)

这里写目录标题 构建工具webpack介绍配置文件简介entryoutputloaderbabel插件开发服务器&#xff08;webpack-dev-server&#xff09;soureMap vite 构建工具 当我们习惯了在node中编写代码的方式后&#xff0c;在回到前端编写html、css、js这些东西会感觉到各种的不便。比如:…

JS代码动态打印404页面源码

JS代码动态打印404页面源码&#xff0c;适合做网站错误页&#xff0c;具有js动态打印效果&#xff0c;喜欢的朋友可以拿去 源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务…

MES系统在装备制造行业核心应用场景介绍

MES软件在企业中有着广泛的应用场景&#xff0c;主要包括生产计划排程、生产过程监控、质量管理、设备管理、库存管理、数据分析等领域。 通过实时监控生产过程、收集数据、进行分析&#xff0c;MES软件可以帮助企业实现生产过程可视化、透明化&#xff0c;提高生产效率&#…

mybatis 延迟加载

MyBatis的延迟加载&#xff08;Lazy Loading&#xff09;是一种优化技术&#xff0c;用于在需要时才加载关联对象或集合&#xff0c;从而提高性能和效率。以下是对MyBatis延迟加载的详细介绍&#xff1a; 延迟加载的基本概念 延迟加载是指在第一次访问对象的属性时才加载该对象…

vue3 antdv Modal通过设置内容里的容器的最小高度,让Modal能够适当的变高一些

1、当收款信息Collapse也折叠的时候&#xff0c;我们会发现Modal的高度也变成了很小。 2、我们希望高度稍微要高一些&#xff0c;这样感觉上面显示的Modal高度太小了&#xff0c;显示下面的效果。 3、初始的时候&#xff0c;想通过class或者style或者wrapClassName来实现&#…

浅谈VPS主机上的数据库性能优化

如何提高网站性能&#xff1f;一个显而易见的解决方案是升级托管账户。您的网站将拥有更多硬件资源&#xff0c;因此可以同时处理更多请求并更快地传递数据。 无论如何&#xff0c;人们都是这么认为的。但事实总是不一样。 现代网站是一个复杂的系统&#xff0c;包含许多必须…

【靶机实战】GeoServer 远程代码执行漏洞复现

# 在线靶场 可以通过访问极核官方靶场开启靶机实验&#xff1a;极核靶场 -> 漏洞复现靶场 -> GeoServer-远程代码执行 原文&#xff1a;【靶机实战】GeoServer 远程代码执行漏洞复现 - 极核GetShell (get-shell.com) # 简介 CVE-2024-36401是一个高危的远程代码执行漏…

java中方法的使用

方法的使用 方法的概念什么是方法方法定义方法的调用过程实参和形参的关系 方法重载为什么需要方法重载方法重载的概念方法签名 递归递归的概念递归过程分析递归练习 方法的概念 什么是方法 方法就是一个代码片段&#xff0c;类似于C语言的函数。 方法存在的意义&#xff1a;…

LabVIEW自动测控与故障识别系统

使用LabVIEW 2019在Win10 64位系统上开发自动测控软件&#xff0c;通过与基恩士NR-X100数据采集仪通讯&#xff0c;实时采集和分析数据&#xff0c;自动识别判断产品是否合格&#xff0c;并增加数据记录和仿真功能。 具体解决方案&#xff1a; 1. 系统架构设计 硬件接口&#…

《AIGC:智能创作时代》:AI创作革命来临,你准备好了吗?

想象一下&#xff0c;你正在欣赏一幅精美的画作&#xff0c;惊叹于其细腻的笔触和独特的构图。然而&#xff0c;当你得知这幅作品是由人工智能创作时&#xff0c;你会作何感想&#xff1f;这不再是科幻小说中的场景&#xff0c;而是我们正在经历的现实。 在这个AI技术飞速发展的…

LT7911UX 国产原装 一拖三 edp 转LVDS 可旋转 可缩放

2.一般说明 该LT7911UX是一种高性能Type-C/DP1.4a到MIPI或LVDS芯片的VR/显示应用。HDCP RX作为HDCP转发器的上游&#xff0c;可以与其他芯片的HDCP TX配合实现转发器功能。 对于DP1.4a输入&#xff0c;LT7911UX可配置为1/2/4通道。自适应均衡使其适用于长电缆应用&#xff0c;最…

2,区块链、数字货币及其应用场景(react+区块链实战)

2&#xff0c;区块链、数字货币及其应用场景&#xff08;react区块链实战&#xff09; 一、什么是区块链&#xff1f;1 ibloackchain&#xff08;1&#xff09;安装ibloackchain&#xff08;2&#xff09;Blance查询余额&#xff08;3&#xff09;Mine挖矿&#xff08;4&#x…

无损音频格式 FLAC 转 MP3 音频图文教程

音频文件的格式多样&#xff0c;每种格式都有其独特的特点与适用场景。FLAC&#xff08;Free Lossless Audio Codec&#xff09;&#xff0c;作为一种无损音频压缩格式&#xff0c;因其能够完美保留原始音频数据的每一个细节而备受音频发烧友和专业人士的青睐。 然而&#xff0…

在表格中选中el-radio后, 怎么获取选中的这一行的所有数据?

演示: 图中, 选中这行数据后, 怎么获取到当前的数据? 代码: <tr v-for"item in gridData"><td><input type"radio" v-model"checkout" change"getDateFn" :data-type"item.articleType" :data-channelNam…

Spring Cloud Alibaba -- 分布式定时任务解决方案(轻量级、快速构建)(ShedLock 、@SchedulerLock )

文章目录 一、 ShedLock简介二、 SchedulerLock三、基于Mysql方式使用步骤1.建表2.引入依赖3.Mysql连接配置4.ScheduledLock配置5.启动类配置6.创建定时任务7.启动多个项目服务进行测试8.SchedulerLock注解说明 四、使用注意事项 一、 ShedLock简介 ShedLock 是一个用于 Java …

中职网络安全B模块渗透测试server2003

通过本地PC中渗透测试平台Kali对服务器场景Windows进⾏系统服务及版本扫描渗透测 试&#xff0c;并将该操作显示结果中Telnet服务对应的端⼝号作为FLAG提交 使用nmap扫描发现目标靶机开放端口232疑似telnet直接进行连接测试成功 Flag&#xff1a;232 通过本地PC中渗透测试平台…

VMware取消中文支持,替换vSAN解决方案提上日程!

What is vSAN &#xff1f; 是一款软件定义的企业存储解决方案&#xff0c;支持超融合基础架构系统。vSAN与VMware vSphere 完全集成在一起&#xff0c;作为ESXi Hypervisor内的分布式软件层&#xff0c;通过整合、池化ESXi各个主机上的存储资源&#xff0c;为vSphere虚拟化平…