信号的产生

news2024/9/25 3:27:45

文章目录

  • 2 信号的产生
    • 2.1 键盘组合键
    • 2.2 命令和函数调用
      • 2.2.1 kill命令
      • 2.2.2 raise()函数
      • 2.2.3 abort()函数
    • 2.3 硬件异常
      • 2.3.1 除0异常
      • 2.3.2 空指针异常
      • 2.3.3 OS如何感知这些异常--除0异常
      • 2.3.4 OS如何感知这些异常--空指针异常
    • 2.4 软件条件
      • 2.4.1 13)SIGPIPE信号
      • 2.4.2 14)SIGALRM信号
      • 2.4.3 用闹钟让程序每隔一段时间打印一段话
      • 2.4.4 闹钟的返回值
    • 2.5 core Dump
      • 2.5.1 引言
      • 2.5.2 代码和结果
      • 2.5.3 设置core file size
      • 2.5.4 作用以及如何使用

2 信号的产生

2.1 键盘组合键

ctrl+c:2号信号

ctrl+\:3号信号

注意,不是所有的信号都能被signal()函数捕捉,如19号信号,9号信号

2.2 命令和函数调用

2.2.1 kill命令

可以在bash中使用,也可以使用下面的系统调用函数

KILL(2)
NAME         
       kill - send signal to a process
LIBRARY         
       Standard C library (libc, -lc)
SYNOPSIS         
       #include <signal.h>
       #include <sys/types.h>
       int kill(pid_t pid, int sig);

模拟实现一下kill命令

// myKill.cc
int main(int argc, char* argv[])
{
    if(argc != 3) {
        cout << "error!" << endl;
        exit(1);
    }
    int sigNum = stoi(argv[1]);
    pid_t pid = stoi(argv[2]);
    int n = kill(pid, sigNum);
    if(n == -1) {
        perror("kill");
        exit(2);
    }
    return 0;
}

image-20240816125118458

2.2.2 raise()函数

raise(3)
NAME         
       raise - send a signal to the caller
LIBRARY        
       Standard C library (libc, -lc)
SYNOPSIS         
       #include <signal.h>

       int raise(int sig);

相当于kill(getpid(), sig)

void MyHandler(int sigNo)
{
    if(sigNo == 2) {
        cout << "Signal 2 two has been captured" << endl;
        exit(2);
    }
}

int main()
{
    // 捕捉该信号,使用SIGINT或者2都可以
    // signal(2, MyHandler);
    signal(SIGINT, MyHandler);
    int cnt = 5;
    while(cnt--) {
        cout << "I am a process, pid: " << getpid() << endl;
        sleep(1);
    }
    raise(SIGINT);
    return 0;
}

image-20240816125844126

2.2.3 abort()函数

abort(3) 
NAME        
       abort - cause abnormal process termination
LIBRARY
       Standard C library (libc, -lc)

相当于给自己发6号信号 6) SIGABRT

void MyHandler(int sigNo)
{
    // if(sigNo == 2) {
    //     cout << "Signal 2 two has been captured" << endl;
    //     exit(2);
    // }
    cout << "Signal has been captured" << endl;
}

int main()
{
    // 捕捉该信号,使用SIGINT或者2都可以
    signal(SIGABRT, MyHandler);
    int cnt = 5;
    while(cnt--) {
        cout << "I am a process, pid: " << getpid() << endl;
        sleep(1);
    }
    abort();
    raise(SIGINT);
    return 0;
}

image-20240816131026361

我们发现,MyHandler()函数并未将该进程退出,而进程却退出了。

image-20240816131236969

当我们使用bash的kill命令时,该进程并未退出。所以该函数有自己的自定义行为(上图已将myProcess程序改为死循环)

2.3 硬件异常

2.3.1 除0异常

image-20240820150933190

// mySignal.cc
void handler(int sigNum)
{
    cout << "Get a signal, num is " << sigNum << endl;
}

int main()
{
    signal(SIGFPE, handler);
    int a = 10;
    cout << "before div" << endl;
    sleep(5);
    a /= 0;
    cout << "after div" << endl;
    return 0;
}

image-20240820151542187

2.3.2 空指针异常

image-20240820151027865

void handler(int sigNum)
{
    cout << "Get a signal, num is " << sigNum << endl;
}

int main()
{
    signal(SIGSEGV, handler);
    int *p = nullptr;
    cout << "before point error" << endl;
    sleep(5);
    *p = 1234;
    cout << "after point error" << endl;
    return 0;
}

image-20240820152229805

可见,进程收到异常信号后,并没有主动退出,而是一直在刷屏打印。所以说捕捉完异常,打印完消息后,最好让该进程退出,使用exit()

关于一直打印的原因,看2.3.3和2.3.4,由于handle()方法并没有退出进程,所以进程一直被调度,每次调度的时候,都会有硬件问题,进程无法执行后序代码,就会一直打信息。

2.3.3 OS如何感知这些异常–除0异常

一些预备知识:

CPU里面有一个状态寄存器(Program Status Word, PSW),用于存储当前处理器的状态信息。这些信息对于控制CPU的操作和行为至关重要。通常包含的状态标志位如下:

  1. 进位标志(Carry Flag)
    • 用于表示算术运算中的进位或借位情况。在加法运算中,如果结果超出了寄存器的大小,进位标志会被设置。
  2. 零标志(Zero Flag)
    • 当算术或逻辑运算的结果是零时,该标志被设置。
  3. 符号标志(Sign Flag)
    • 用于表示最近一次算术运算结果的符号。在有符号数运算中,如果结果是负数,符号标志会被设置。
  4. 溢出标志(Overflow Flag)
    • 用于表示算术运算中的溢出情况。当运算结果超出了寄存器的表示范围时,溢出标志被设置。
  5. 奇偶校验位(Parity Flag)
    • 用于表示最近一次运算结果的最低有效字节中1的个数。如果1的个数是偶数,则奇偶校验位被设置。
  6. 辅助进位标志(Auxiliary Carry Flag)
    • 在某些CPU架构中,辅助进位标志用于表示在BCD(二进制编码的十进制)运算中的进位情况。
  7. 中断使能标志(Interrupt Enable Flag)
    • 控制CPU对中断的响应。如果该标志被设置,CPU将允许中断;如果被清除,则CPU将忽略中断请求。
  8. 方向标志(Direction Flag)
    • 在某些CPU架构中,方向标志用于确定字符串操作(如串行比较或复制)的方向。
  9. 陷阱标志(Trap Flag)
    • 在某些CPU架构中,陷阱标志用于控制异常或陷阱的生成。

PC(Program Counter):PC是一个通用术语,用于描述大多数CPU架构中用于存储下一条指令地址的寄存器。

EIP(Extended Instruction Pointer):EIP是x86架构CPU中的一个寄存器,用于存储下一条将要执行的指令的内存偏移地址。它是在实模式和保护模式下使用的。在64位的x86-64架构中,EIP被扩展为RIP(Register Instruction Pointer),是一个64位寄存器。

在讨论x86架构时,我们使用EIP(或RIP在x86-64架构中);而在讨论其他架构时,我们可能会使用PC来描述类似的功能。


进程上下文,是指操作系统在某一时刻为执行当前进程所准备和维护的一组数据和状态信息。上下文包括所有CPU寄存器的值、程序计数器、程序状态字、堆栈指针、内存管理信息、I/O状态等,这些信息共同定义了当前进程的执行状态

进程上下文切换发生在CPU从执行一个进程切换到执行另一个进程时。上下文切换涉及保存当前进程的上下文,加载新进程的上下文,然后将控制权传递给新进程。上下文切换是操作系统多任务处理机制的核心部分,允许多个进程共享同一台机器的CPU资源

上下文切换包括但不限于以下步骤:

  1. 保存当前进程的寄存器和状态信息。
  2. 更新当前进程的内存管理信息。
  3. 将控制权转交给操作系统的调度器。
  4. 调度器选择另一个进程执行。
  5. 加载新选中进程的上下文到CPU。
  6. 恢复新进程的执行,从上次离开的地方继续运行。

image-20240820161325048

CPU也是硬件,OS是硬件的管理者,当出现异常时,OS有权利也有义务知道

2.3.4 OS如何感知这些异常–空指针异常

CPU上集成了一个MMU单元

MMU(Memory Management Unit,内存管理单元)是计算机体系结构中的一个重要组件,负责管理CPU与内存之间的交互。MMU的主要功能包括:

  1. 地址转换:MMU将程序使用的逻辑地址或虚拟地址转换为物理地址,这个过程称为地址翻译。这使得多个进程可以同时运行在同一个物理内存上,而不会相互冲突。
  2. 内存保护:MMU可以为不同的内存区域设置保护属性,确保进程不能访问不属于它的内存区域,从而防止内存破坏和数据泄露。
  3. 内存访问控制:MMU控制对内存的访问权限,例如区分可读、可写和可执行权限,以及用户模式和内核模式的访问权限。
  4. 分页管理:在支持分页的系统中,MMU使用页表来管理虚拟地址到物理地址的映射。页表包含了虚拟页和物理页之间的对应关系。
  5. 缓存管理:MMU与CPU缓存协同工作,管理数据的缓存和一致性,确保CPU访问的是最新和正确的数据。
  6. 内存分配:在某些系统中,MMU还参与内存的分配和回收,例如在分页系统中,MMU可以跟踪哪些内存页正在使用,哪些是空闲的。
  7. 异常处理:当发生内存访问违规时,如访问不存在的页面或违反访问权限,MMU会触发异常或中断,操作系统将捕获这些异常并进行处理。
  8. 透明扩展:在32位系统中,MMU可以提供对更大物理内存的支持,即使CPU的地址总线不足以直接寻址所有物理内存。

image-20240820173119274

CPU也是硬件,OS是硬件的管理者,当出现异常时,OS有权利也有义务知道

2.4 软件条件

2.4.1 13)SIGPIPE信号

看[该文章](进程间通信-CSDN博客的2.6,上面介绍了,当管道的读端关闭,写端便会变得没有意义,OS会给写端发一个13)SIGPIPE信号

2.4.2 14)SIGALRM信号

看下面的函数

alarm(2)                   System Calls Manual                  
NAME         
       alarm - set an alarm clock for delivery of a signal
LIBRARY        
       Standard C library (libc, -lc)
SYNOPSIS         
       #include <unistd.h>

       unsigned int alarm(unsigned int seconds);
DESCRIPTION         
       alarm() arranges for a SIGALRM signal to be delivered to the
       calling process in seconds seconds.

       If seconds is zero, any pending alarm is canceled.

       In any event any previously set alarm() is canceled.
    
       alarm()将SIGALRM信号以秒为单位发送给调用进程。
       如果seconds为0,则任何待处理的告警将被取消。
       在任何情况下,之前设置的alarm()都会被取消。
RETURN VALUE         
       alarm() returns the number of seconds remaining until any
       previously scheduled alarm was due to be delivered, or zero if
       there was no previously scheduled alarm.
       Alarm()返回任何先前计划的闹钟所剩余的秒数,如果没有先前计划的闹钟,则返回零。
void handler(int sigNum)
{
    cout << "Get a signal, num is " << sigNum << endl;
    exit(1);
}

int main()
{
    signal(SIGALRM, handler);
    alarm(5);       // 5s后发信号
    while(true) {
        cout << "Process is running" << endl;
        sleep(1);
    }
}

image-20240820185251706

当我们去掉上面第4行的exit(1);后,会:

image-20240820185510774

发现并没有一直刷屏,因为闹钟不是异常,响了就没有然后了。

2.4.3 用闹钟让程序每隔一段时间打印一段话

void work()
{
    cout << "this is log..." << endl;
}

void handler(int sigNum)
{
    work();
    alarm(5);
}

int main()
{
    signal(SIGALRM, handler);
    alarm(5);       // 5s后发信号
    while(true) {
        cout << "Process is running" << endl;
        sleep(1);
    }
    return 0;
}

image-20240820190157252

2.4.4 闹钟的返回值

void work()
{
    cout << "this is log..." << endl;
}

void handler(int sigNum)
{
    work();
    int n = alarm(5);
    cout << "上一个闹钟的剩余时间" << n << endl;
}

int main()
{
    signal(SIGALRM, handler);
    alarm(100);      
    int cnt = 0; 
    while(true) {
        cout << "Process is running" << endl;
        cnt++;
        sleep(1);
        if(cnt == 5) 
        raise(SIGALRM);
    }
}

image-20240820202445817

2.5 core Dump

2.5.1 引言

使用man 7 signal命令

image-20240820205355225

看到Action里有Term和Core
之前在学习进程等待时,有这个图

image-20240820205458788

core dump标志就是用来标志被信号所杀的进程所收到的信号的ActionTerm还是Core

2.5.2 代码和结果

现在有下面的代码

pid_t id = fork();
if(id == 0) {
    // child
    while (true)
    {
        cout << "I am child, pid is " << getpid() << endl;
        sleep(1);
    }
}
// father
int status = 0;
pid_t rid = waitpid(id, &status, 0);
if(rid == id) {
    cout << "child quit info\nrid: " << rid << " exit signal: " << (status & 0x7f)
        << " core dump:" << ((status >> 7) & 1) << endl;
}

运行这个进程,分别使用Action为TermCore的终止这两个进程

image-20240826193207169

image-20240826193410864

可以看到,即便使用了3号Action为Core的信号,core dump仍然是0

这是因为在云服务器中,core功能默认是关闭的
image-20240826193921622

2.5.3 设置core file size

可以使用ulimit -c [size]来设置大小
image-20240826194407597

设置完成之后再来实验

image-20240826194539948

image-20240826194704551

不但core dump被设置,而且生成了一个文件

打开系统的core dump(核心转储)功能,一旦进程出异常,OS会将进程在内存中的运行信息,给我dump(转储)到进程的当前目录(磁盘)
形成core.pid文件

2.5.4 作用以及如何使用

作用就是当代码出现运行时错误时,可以详细知道是哪一行,出现了什么错误

使用的时候需要g++的参数,加上-g,告诉GCC产生能被GNU调试器使用的调试信息,以调试程序

修改一下程序

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

using namespace std;

int main()
{
    int a = 10;
    int b = 0;
    a /= b;
    cout << "a=" << a << endl;
    return 0;
}

image-20240826200632820

当出现运行时错误时,这种方式可以直接定位到出错行。先运行,再调试,这属于事后调试

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

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

相关文章

yolov5关键点检测-实现溺水检测与警报提示(代码+原理)

基于YOLOv5的关键点检测应用于溺水检测与警报提示是一种结合深度学习与计算机视觉技术的安全监控解决方案。该项目通常会利用YOLOv5强大的实时目标检测能力&#xff0c;并通过扩展或修改网络结构以支持人体关键点检测&#xff0c;来识别游泳池或其他水域中人们的行为姿态。 项…

12-使用gateway作为微服务网关

本文介绍spring gateway的使用&#xff0c;包括配置文件和使用java代码配置&#xff0c;让大家了解spring gateway的用法。如果不了解什么是微服务网关&#xff0c;就先查查资料&#xff0c;网关相对来说是比较重要的微服务组件。 0、环境 springboot 2.4.2springcloud gatew…

游戏开发设计模式之装饰模式

目录 装饰模式在游戏开发中的具体应用案例是什么&#xff1f; 如何在Unity中实现装饰模式以动态扩展游戏对象的功能&#xff1f; 装饰模式与其他设计模式&#xff08;如适配器模式、代理模式&#xff09;相比&#xff0c;有哪些优势和劣势&#xff1f; 优势 劣势 与适配器…

唯众2024年高职人工智能实训室方案解读

随着人工智能&#xff08;AI&#xff09;技术在全球范围内的快速发展&#xff0c;越来越多的职业技术学院开始重视AI相关专业的建设和实训室的搭建。作为在人工智能教育领域有着丰富经验的企业&#xff0c;唯众针对2024年的市场需求&#xff0c;推出了一套全面的人工智能实训室…

软件设计师教程(第5版)第8章 算法设计与分析(更新中)

8.1 算法设计与分析的基本概念P416 8.1.1 算法P416 【算法】是对特定问题求解步骤的一种描述&#xff0c;它是指令的有限序列&#xff0c;其中每一条指令表示一个或多个操作。P416 一个算法还具有下列5个重要特性&#xff1a;【有穷】性、【确定】性、【可行】性、【输入】、…

Games101学习 - 线性代数综述

1. 叉积矩阵形式 叉乘矩阵形式通常在物理模拟中有运用&#xff0c;处理四元数旋转也类似这样的形式。 // 定义两个向量 A 和 B FVector A(1.0f, 2.0f, 3.0f); FVector B(4.0f, 5.0f, 6.0f);// 计算叉积 FVector CrossProduct FVector::CrossProduct(A, B);if (GEngine) {GEn…

CVPR2024满分论文:基于可变形三维高斯的高质量单目动态重建方法

一、摘要 隐式神经表征为动态场景的重建和渲染开辟了新的途径。然而&#xff0c;尖端的动态神经渲染方法严重依赖这些隐式表征&#xff0c;它们常常难以捕捉场景中物体的复杂细节。此外&#xff0c;隐式方法通常难以实现动态场景的实时渲染&#xff0c;限制了它们在多种任务中的…

Excel公式与图表自动化:在Python中操作Excel公式并自动化生成图表

目录 一、Python操作Excel公式 1.1 读取Excel文件 1.2 识别和处理公式 1.3 批量处理公式 二、自动化生成图表 2.1 使用pandas和matplotlib生成图表 2.2 使用xlwings在Excel中直接生成图表 2.3 自定义图表样式 2.4 自动化生成复杂图表 三、总结 在数据分析和自动化办公…

VMware Workstation Pro for Personal Use (For Windows) 17.0.0

VMware Workstation Pro for Personal Use (For Windows) 17.0.0 弄了半天终于找到下载地址了 现在VMware被博通&#xff08;broadcom&#xff09;收购且宣布了17.5版本的VMware Workstation Pro对个人用户免费许可使用。由于现在官网的下载方式有改变&#xff0c;故贴出来一…

【数学分析笔记】第2章第4节收敛准则(4)

2.数列极限 2.4 收敛准则 上节课举了一个例子 a N 1 1 2 p 1 3 p . . . 1 n p a_{N}1\frac{1}{2^{p}}\frac{1}{3^{p}}...\frac{1}{n^{p}} aN​12p1​3p1​...np1​ p > 1 p>1 p>1&#xff0c; { a n } \{a_{n}\} {an​}收敛 0 < p ≤ 1 0<p\le 1 0<p≤…

OpenStack——keystone认证服务

1、作用 认证授权 服务目录 2、组件 keystone-server keystone-DB 3、架构 ①组成 用户认证流程&#xff1a; 1.Horizon为用户提供界面; 2.用户输入用户名密码&#xff0c;有Horizon转发至Keystone做认证授权 ; 3.如果认证鉴权成功&#xff0c;会给用户发放一个临时的unscope…

AIGC:Flux.1 NF4 使用 diffusers 推理

背景介绍 Flux 参数量很大 (包括 ext encoder2, autoencoder, 以及 diffusion model) , 使用Diffusers推理,显存占用 30GB。 有大佬做了 NF4 版本,效果依旧能打。所以本文使用 diffusers 推理 NF4版本的 Flux.1 本文重点 1:flux.1-dev-nf4 国内镜像加速下载 2:依赖环境…

error: undefined reference to `__imp__ZN11QSerialPortC1EP7QObject‘

问题 在qt console程序里使用QSerialPot, 在.pro文件里添加了serialport&#xff0c;在main.cpp里也包含了QtSerialPort/QSerialPort&#xff0c;但是编译报错如下&#xff1a; 原因 serialport模块加错了位置&#xff0c;应该添加到QT后面&#xff0c;而实际添加到CONFIG后…

mybatis-plus中Swagger 模式和Kotlin 模式是什么?

在 MyBatis-Plus 中&#xff0c;Swagger 模式和 Kotlin 模式是为了支持特定技术栈和开发需求的两种配置选项。它们分别针对 API 文档生成和 Kotlin 语言提供了更好的支持和集成。 Swagger 模式 Swagger 模式主要用于生成 API 文档。在 MyBatis-Plus 中启用 Swagger 模式后&am…

视频合并怎么弄?高效方法立即学

记得那次家庭聚会&#xff0c;我翻看着那些珍贵的录像带&#xff0c;突然萌生了一个想法&#xff1a;要是能把这些零散的记忆片段合并成一部完整的影片&#xff0c;那该多好啊&#xff01; 于是我开始了视频合并剪辑的探索之旅。从一开始的手足无措&#xff0c;到逐渐熟悉每一…

linux,ubuntu,使用ollama本地部署大模型llama3,模型通用,简易快速安装

文章目录 前言安装ollama启动ollama运行llama3模型查看ollama列表删除模型通过代码进行调用REST API 前言 在拥有了一条4090显卡后&#xff0c;那冗余的性能让你不得不去想着办法整花活&#xff0c;于是就想着部署个llama3&#xff0c;于是发现了ollama这个新大陆&#xff0c;…

【硬件操作入门】2--GPIO与门电路、二极管三极管、LED电路与操作

【硬件操作入门】2–GPIO与门电路&#xff08;二极管&三极管&#xff09;、LED电路与操作 文章目录 【硬件操作入门】2--GPIO与门电路&#xff08;二极管&三极管&#xff09;、LED电路与操作一、GPIO与门电路1.1、GPIO的应用1.2、GPIO引脚操作1.2.1 设置引脚为GPIO功能…

今日算法:蓝桥杯基础题之“切面条”

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注&#xff01;个人知乎 从今天开始&#xff0c;一起了解算法&#xff0c;每日一题&#xff0c;从 JavScript 的技术角度进行解答&#xff0c;如果你对算法也感兴趣&#xff0c;请多多关注哦。 问题描述 一…

网络维护~2003服务环境

一、2003服务环境 背景&#xff1a;学习测试需要在虚拟机进行实验&#xff0c;主机kali验证开源十大漏洞&#xff0c;部分需要2003服务环境。 博客声明:搭建网络是为了学习用途&#xff0c;请遵守《网络安全法》. 二、安装iis服务软件 &#xff08;一&#xff09;查看Internet…

重生奇迹MU 单挑团战全能的职业

若你正在寻找一款能够在重生奇迹MU单挑或团战中表现不怂的职业&#xff0c;那么恭喜你&#xff0c;你来到了正确的地方。在本文中&#xff0c;我们将为你介绍几个在重生奇迹MU中表现出色的职业&#xff0c;并分享一些有用的技巧和策略&#xff0c;帮助你在游戏中获得胜利。不用…