当前位置: 首页 > news >正文

Linux信号的产生

Linux系列


文章目录

  • Linux系列
  • 一、信号的产生
    • 1.1 异常
    • 1.2 alarm()系统调用
  • 二 、信号的默认行为


一、信号的产生

上篇文章我们已经介绍了信号的三种产生方式,这部分是对上篇文章的补充

1.1 异常

在编写程序时,我们的程序经常会出现如:除零错误、野指针错误,导致进程崩溃,而进场崩溃的根本原因就是因为OS向我们的进程发送了信号,下面我们通过两个例子详细分析:

例一

#include<iostream>using namespace std;
int main()
{int a=10;int b=0;int c=a/b;cout<<"sucess!!!"<<endl;return 0;
}

在这里插入图片描述
可以看到当程序发生除零错误后,直接崩溃不会再执行下面代码。

在这里插入图片描述
上图信息通过:man 7 signal 查找得到
从上图可以看出进程是接受到八号信号,而退出的,下面我们通过捕捉来验证:

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;void handler(int numsig)
{cout<<"I capture a signal:"<<numsig<<endl;sleep(1);return ;
}
int main()
{signal(8,handler);int a=10;int b=0;int c=a/b;return 0;
}

在这里插入图片描述
我们能看到进程确实收到了8号信号,但是我们并没有写循环为什么handler方法一直被执行呢?OS又是如何判断要给进程发送8号信号的?
在这里插入图片描述
CPU中存在很多寄存器,当CPU执行程序,执行到除零运算时,状态寄存器的溢出标志位被置位(1),CPU发生硬件中断产生中断号,被OS识别,操作系统根据中断向量表给进程发送信号,信号被进程捕捉执行我们自己的方法,执行完毕返回进程并没有被退出,进程继续被调度,但是进程上下文数据并没有修改,溢出标志位一直为1,OS 一直发送信号…,这样就表现为handler方法一直被调度。

例二

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;// void handler(int numsig)
// {
//     cout<<"I capture a signal:"<<numsig<<endl;
//     sleep(1);
//     return ;
// }
int main()
{//signal(8,handler);int *p=nullptr;//野指针*p=2;return 0;
}

在这里插入图片描述
当进程发生野指针错误时,进程也会直接崩溃,此时进程接收到的是11号信号,你可以自己查看这里就不展示了。

在这里插入图片描述
当你对该信号捕捉执行自定义方法,如果不退出进程,结果依然表现为handler方法一直被调用。

在这里插入图片描述
当我们内存访问时,CPU中存在存在一个MMU内存管理单元,帮助我们把虚拟地址转化为物理地址,当转化失败(对该内存没有权限、不存在等)时,就会将转化失败的虚拟内存地址存放到CPU寄存器中,OS检测到后给进程发送信号。我们对于异常的处理,一般都为终止进程,并不会尝试修复它,而这些异常信号可以被捕获,是OS方便用户对数据进行处理(保存、日志等)的。

上面的两个例子都是由硬件产生的,但是异常还可以由软件产生,这点我在管道部分介绍过了,下面会直接用作示例来介绍新的知识。

1.2 alarm()系统调用

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

功能:设定一个定时器,在指定的秒数后向进程发送SIGALRM信号。

参数

  • seconds:如果不为0在经过seconds秒后,进程会收到SIGALRM信号。如果在定时器到期之前再次调用alarm函数,会重新设置定时器,之前剩余的时间被忽略,如果为0,定时器被取消,之前设置的任何未到期的定时器都会被清除,且不会发送信号。

返回值

  • 返回上一次设置定时器的剩余秒数,如果之前设置的定时器已经过期返回0.

示例:

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;void work()
{cout<<"起床了!!!"<<endl;
}
void handler(int numsig)
{work();//执行闹钟任务return ;
}
int main()
{signal(SIGALRM,handler);//捕捉信号,执行自定义任务alarm(5);//5秒后给进程发送SIGALRM信号int cnt=0;while(1){cout<<cnt++<<endl;sleep(1);}return 0;
}

在这里插入图片描述
可以看到当我们的程序设置闹钟后,就可以通过捕捉信号,完成指定任务的执行行,这种方式我们一般用来格一段时间,来打印一次日志信息。

这个别看:闹钟什么时候触发依赖于时间戳,对闹钟进行管理。。填充闹钟结构体属性。。。管理闹钟结构体。。系统维护当前时间。。。对比是否超时。。。堆结构,提高比较效率。。。。

二 、信号的默认行为

在这里插入图片描述

  • Term:表示该信号的默认行为是终止进程。

  • Core:意味着信号触发时,进程在终止的同时,会产生核心转储(Core Dump)文件,用于后续调试分析。

在我们介绍进程控制时,就遇到过了这个问题:

在这里插入图片描述
下面我们来尝试获取这个标志,另外我们需要先将服务器Core 权限打开
在这里插入图片描述
在这里插入图片描述
后面就需要根据你自己的系统配置了,大家可以结合自己的系统搜索以下,我们直接跳入使用部分:
在这里插入图片描述
这样我们就可以直接使用,生成的转储文件,结合gdb调试工具,对错误信息进行,快速定位了。这种调试方法我们称为事后调试。

本篇内容比较乱,主要是用来总结、整合前面的知识的。

相关文章:

  • 安卓投屏软件QtScrcpy
  • 基于nlohmann/json 实现 从C++对象转换成JSON数据格式
  • 麒麟V10安装MySQL8.4
  • AT24C02芯片简介:小巧强大的串行EEPROM存储器
  • 音视频学习 - MP3格式
  • 鸿蒙开发:Swiper轮播图
  • 【Rust】基本概念
  • Anaconda3使用conda进行包管理
  • 支持AVX2指令的计算机,ONNX推理量化模型比推理浮点模型慢?
  • 基于javaweb的SSM教材征订与发放管理系统设计与实现(源码+文档+部署讲解)
  • 携程-酒旅-数据研发面经【附答案】
  • go语言中defer使用指南
  • 逻辑思维:从混沌到秩序的理性推演在软件开发中的应用
  • 使用Nacos 打造微服务配置中心
  • Go语言之sync包 WaitGroup的使用和底层实现
  • 文件操作函数
  • 基于cubeMX的hal库STM32实现硬件IIC通信控制OLED屏
  • 汽车VIN码识别:解锁汽车行业的智能密码
  • Spark-SQL 项目
  • 爬虫(requests库,logging库)
  • 央行:25日将开展6000亿元MLF操作,期限为1年期
  • 北京市平谷区政协原主席王春辉接受纪律审查和监察调查
  • 国防部:“台独”武装摆练纯属搞心理安慰,怎么演都是溃败的死局
  • 冲击一英里4分钟大关,基普耶贡挑战女子中长跑极限
  • 梁启超“失肾记”的余波:中西医论战与最后的真相
  • 内蒙古镶黄旗委原书记好毕斯哈拉图履新锡林郭勒盟民政局局长