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

news2024/10/1 3:26:02

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.coloradmin.cn/o/1913145.html

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

相关文章

【深度学习基础】MAC pycharm 专业版安装与激活

文章目录 一、pycharm专业版安装二、激活 一、pycharm专业版安装 PyCharm是一款专为Python开发者设计的集成开发环境&#xff08;IDE&#xff09;&#xff0c;旨在帮助用户在使用Python语言开发时提高效率。以下是对PyCharm软件的详细介绍&#xff0c;包括其作用和主要功能&…

11、Python之变量:看得见还是看不见

引言 在前面一篇关于Python变量的文章中&#xff0c;更多地结合对象的内存结构及字节码指令&#xff0c;来看不同代码针对不同的类型的对象的不同效果。 今天这篇文章中&#xff0c;想对新手在使用Python变量中&#xff0c;可能遇到的其他困惑&#xff0c;再展开来说一下。 大…

Windows近源攻击应急响应

一、靶机介绍 Windows近源攻击 前景需要&#xff1a;小王从某安全大厂被优化掉后&#xff0c;来到了某私立小学当起了计算机老师。某一天上课的时候&#xff0c;发现鼠标在自己动弹&#xff0c;又发现除了某台电脑&#xff0c;其他电脑连不上网络。感觉肯定有学生捣乱&#x…

量子保密通信协议原理:量子保密通信实验

纸上得来终觉浅&#xff0c;绝知此事要躬行。 在之前的文章中&#xff0c;我们对量子密钥分发协议原理、分发过程进行了详细的描述&#xff0c;今天我们实操一波。博主向大家隆重介绍一下华中师范大学量子保密通信虚拟仿真试验平台&#xff1a;量子保密通信是将量子密钥分发和一…

旷野之间2 - 如何训练医疗保健小型语言模型(AI-SLM)

​​​​ 在本文中,我们将研究如何针对疾病症状训练一个小型医疗保健语言模型。为此,我们将从HuggingFace获取数据集(用于训练我们的模型):https://huggingface.co/datasets/QuyenAnhDE/Diseases_Symptoms QuyenAnhDE/Diseases_Symptoms 数据集来自 Hugging Face。图片来源…

SAP 报工BAPI中的 UPDATA TASK 和 BACKGROUND TASK

前言&#xff1a; 记录这篇文章起因是调查生产订单报工问题引申出来的一个问题&#xff0c;后来再次调查后了解了其中缘由&#xff0c;大概记录以下&#xff0c;如有不对&#xff0c;欢迎指正。问题原贴如下&#xff1a; SAP CO11N BAPI_PRODORDCONF_CREATE_TT连续报工异步更…

记一次java进程异常退出原因排查

最近在对一个Java服务进行压测&#xff0c;但是压测一段时间后&#xff0c;java进程就会自动停止&#xff0c;虽然怀疑可能是内存不足原因导致的&#xff0c;但是从服务日志中去看&#xff0c;并没有OOM的相关报错日志。这就很奇怪了&#xff01;然后就从Java启动参数入手&…

MQTT教程--服务器使用EMQX和客户端使用MQTTX

什么是MQTT MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级、基于发布-订阅模式的消息传输协议&#xff0c;适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它在物联网应用中广受欢迎&#xff0c;能够实现传感器、执行器和其它设备…

WPF依赖附加属性

依赖附加属性的定义 基本过程&#xff1a;声明、注册、包装 依赖附加属性必须在依赖对象&#xff0c;附加属性不一定&#xff0c;关注的是被附加的对象是否是依赖对象 快捷方式&#xff1a;propa tab 关键字&#xff1a;RegisterAttached // 方法封装 public static int …

【系统架构设计师】九、软件工程(需求工程|系统分析与设计|DFD|DD|高内聚低耦合)

目录 四、需求工程 4.1 软件需求层次 4.2 软件需求 4.3 需求获取 4.4 需求分析 4.5 需求定义 4.6 需求确认与验证 4.7 需求管理 4.7.1 变跟控制 4.7.2 需求追踪 五、系统分析与设计 5.1 结构化方法 5.1.1 结构化需求分析 5.1.2 数据流图DFD 5.1.3 数据字典DD …

外卖商城平台小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商家管理&#xff0c;骑手管理&#xff0c;商品类型管理&#xff0c;商品信息管理&#xff0c;订单信息管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;商品信息&#…

完美解决ImportError: cannot import name ‘idnadata‘的正确解决方法,亲测有效!!!

完美解决ImportError: cannot import name idnadata’的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 亲测有效 完美解决ImportError: cannot import name idnadata的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01;报错问题…

灭世男孩

《血腥复仇与反乌托邦之旅&#xff1a;<灭世男孩>的暴力美学盛宴》 在众多电影的海洋中&#xff0c;有一部独特而引人注目的作品——《灭世男孩》。这部由德国、南非和美国联合制作的电影&#xff0c;以其独特的风格、精彩的动作场面和深刻的主题&#xff0c;为观众带来了…

Studio One直播声音怎么调 Studio One直播没有声音输出怎么办 studio one如何设置声音变好听

Studio One做为新生代音乐工作站&#xff0c;凭借更低的价格和完备的功能&#xff0c;获得了音乐人和直播行业工作者的青睐&#xff0c;尤其是对硬件声卡的适配支持更好&#xff0c;特别适合用来配合线上教学和电商带货。 一、Studio One直播声音怎么调 在Studio One进行直播时…

odoo17 常见升级问题

通用问题 模型名变更 字段变更 方法名变更 方法参数变更 xml数据结构定义变化 xml的id变更 view视图变化&#xff0c;导致xpath路径出差 template结构变化&#xff0c;&#xff0c;导致xpath路径出差&#xff0c;或者id不存在 升16问题 前端owl的架构变化 升17问题 前端 标…

OJhelper一款帮助你获取各大oj信息的软件

项目地址 应用功能 目前应用支持&#xff1a;查询、自定义、收藏各大oj比赛信息&#xff0c;跳转比赛界面。查询各大oj的Rating分以及题量&#xff0c;查看题量饼状图。 应用环境 windows和安卓端 应用预览&#xff1a; 维护概况 后期会提供持续更新&#xff0c;具体可以…

回溯算法-以医院信息管理系统为例

1.回溯算法介绍 1.来源 回溯算法也叫试探法&#xff0c;它是一种系统地搜索问题的解的方法。 用回溯算法解决问题的一般步骤&#xff1a; 1、 针对所给问题&#xff0c;定义问题的解空间&#xff0c;它至少包含问题的一个&#xff08;最优&#xff09;解。 2 、确定易于搜…

压缩感知3——重构算法正交匹配追踪算法

算法流程 问题的实质是&#xff1a;AX Y 求解&#xff08;A是M维&#xff0c;Y是N维且N>>M并且稀疏度K<M&#xff09;明显X有无穷多解&#xff0c;重构过程是M次采样得到的采样值升维的过程。OMP算法的具体步骤&#xff1a;(1)用X表示信号&#xff0c;初始化残差e0 …

人工智能算法工程师(中级)课程2-Opencv视觉处理之高级操作

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程2-Opencv视觉处理之高级操作。在上一节课中的OpenCV基础操作我们了解到OpenCV是一个开源的计算机视觉软件库。它提供了各种视觉处理函数&#xff0c;并支持多种编程语言&#xff0c;如…

鸿蒙语言基础类库:【@ohos.util (util工具函数)】

util工具函数 说明&#xff1a; 本模块首批接口从API version 7开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 该模块…