【Linux】:信号与信号产生

news2024/11/24 17:30:45

朋友们、伙计们,我们又见面了,本期来给大家带来信号和信号的产生相关代码和知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

目录

1. 信号概念

2. 信号的产生

① 前台进程

② 后台进程

2.1 信号的产生方式

① 通过键盘产生

② 通过系统调用产生 

③ 通过硬件异常产生 

④ 通过软件条件产生

3. 核心转储(core dump) 


1. 信号概念

从生活的角度来说:

道路边的红绿灯信号、上下课的铃声、古时候的狼烟、旗语、手机的来电铃声等等;

当这些信号出现的时候我们可以识别并下意识的做出对应的反应。

在Linux角度来说:

在命令行输入kill -l就可以查看系统可支持的信号列表;

当我们程序运行起来,我们直接使用Ctrl + c 就可以终止进程,这也叫做信号。

  • ① 信号没有产生的时候,其实我们已经知道怎么来处理这个信号;
  • ② 信号什么时候来,我们并不清楚,信号的到来相对于我目前做的工作来说是异步产生的;
  • ③ 信号产生了,我们不一定要立即处理他,而是等到合适的时机来处理;
  • ④ 信号到来到我要处理信号的期间,我们需要对已经到来的信号进行暂时保存。

信号是向目标进程发送通知消息的一种机制。 

2. 信号的产生

在谈论信号的产生之前先来了解一下Linux中的前、后台进程:

① 前台进程

在命令行中我们输入./exe启动一个进程时启动的是前台进程;

我们自己的程序以前台进程的方式运行,此时我们输入指令时是没有任何效果的!

shell也是一个进程,我们使用命令行时使用的就是shell这个前台进程,所以当使用./exe运行程序时,OS就会自动将shell放到后台,前台进程只能有一个。

一般情况下:Ctrl + c 终止前台进程

Ctrl + \ :终止前台进程

② 后台进程

在命令行输入./exe & 以后台程序的方式运行;

后台进程可以有多个,使用 jobs命令查看所有的后台进程:

使用 fg 任务编号:将指定的后台进程提到前台

前台进程不能被暂停,如果我们正常运行起来的前台进程使用Ctrl + z时暂停,会将该进程必须放到后台;

使用bg 任务编号:将指定后台进程运行起来。

2.1 信号的产生方式

在命令行输入kill -l可以查看所有信号;

没有0号信号,因为在我们程序运行结束之后,成功返回的是0。

信号有对应的编号和名称,我们既可以使用编号又可以使用名称。

1 ~ 31叫做普通信号,34 ~ 64叫做实时信号。

向目标进程发送信号时,对于普通信号来讲,该进程如何知道自己是否收到某种信号?

在进程的PCB中维护一张位图,并且每个进程都有一张函数指针数组表,数组下标和信号编号强相关;

位图中比特位的位置决定信号的编号;

           比特位的内容决定是否收到该信号。

当进程收到指定信号时,先去位图中查找对应的信号,然后通过信号编号在函数指针数组中执行对应的方法。

因为OS是进程的管理者,无论信号的产生方式有多少种,永远只能由OS向目标进程发送。

发信号其实是向位图中写入(对对应的比特位操作) 

信号的本质:用软件来模拟硬件与CPU之间的中断行为!

① 通过键盘产生

我们在命令行./exe运行起来的进程,当我们在键盘上敲下Ctrl + c组合键时,该进程就会被终止,此时我们从键盘上输入Ctrl + c就是向该进程发送指定的信号。

在合适的时候处理信号的有三种情况:

  • 1. 信号的默认行为
  • 2. 忽略该信号
  • 3. 自定义行为(信号的捕捉)

signal接口可以用于捕捉信号去执行自定义函数方法:

我们输入的Ctrl + c其实是2号信号,输入的Ctrl + z其实是20号信号,输入的Ctrl + /其实是3号信号,接下来我们可以采用信号捕捉的方式来验证一下:

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
using namespace std;

// 自定义行为的函数返回值必须是void,参数必须是int类型
void handler(int signo)
{
    while (true)
    {
        std::cout << "这是一个" << signo << "号信号" << std::endl;
        sleep(1);
    }
}

int main()
{
    signal(2, handler); // 捕捉2号信号
    signal(3, handler); // 捕捉3号信号
    signal(20, handler);// 捕捉20号信号

    while (1)
    {
        cout << "running ...., pid: " << getpid() <<endl;
        sleep(1);
    }
    return 0;
}

9号信号不可被捕捉,即便是我们使用signal接口进行捕捉,也不能让9号信号执行自定义方法!

② 通过系统调用产生 

kill接口:向指定进程发送指定的信号

让我们自己的进程运行5s,然后使用kill系统调用来发送2号信号;

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
using namespace std;

void handler(int signo)
{
    while (true)
    {
        std::cout << "这是一个" << signo << "号信号" << std::endl;
        sleep(1);
    }
}

int main()
{
    signal(2, handler); // 捕捉2号信号
    int cnt = 5;
    while (cnt--)
    {
        cout << "running ...., pid: " << getpid() << endl;
        sleep(1);
    }
    // kill(getpid(), SIGINT); 
    // 系统调用接口产生信号
    kill(getpid(), 2);
    return 0;
}

raise接口:自己给自己发送指定的信号

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
using namespace std;

// 自定义行为的函数返回值必须是void,参数必须是int类型
void handler(int signo)
{
    while (true)
    {
        std::cout << "这是一个" << signo << "号信号" << std::endl;
        sleep(1);
    }
}

int main()
{
    signal(3, handler); 
    int cnt = 5;
    while (cnt--)
    {
        cout << "running ...., pid: " << getpid() << endl;
        sleep(1);
    }
    // 给自己发送3号信号
    raise(SIGQUIT);
    return 0;
}

abort接口:使当前进程收到信号并异常终止

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
using namespace std;

// 自定义行为的函数返回值必须是void,参数必须是int类型
void handler(int signo)
{
    while (true)
    {
        std::cout << "这是一个" << signo << "号信号" << std::endl;
        sleep(1);
    }
}

int main()
{
    signal(6, handler); // 捕捉2号信号
    int cnt = 5;
    while (cnt--)
    {
        cout << "running ...., pid: " << getpid() << endl;
        sleep(1);
    }

    abort(); // 收到6号信号

    return 0;
}

③ 通过硬件异常产生 

异常产生的信号比如常见的段错误、野指针问题;

在这里演示一下常见的除0错误产生的信号:

当发生除0异常时,OS直接向进程发生8号信号来终止进程。

接下来我们捕捉一下8号信号看看会发生什么:

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
using namespace std;

void handler(int signo)
{
    // 注意这里没有循环
    std::cout << "这是一个" << signo << "号信号" << std::endl;
    sleep(1);
}

int main()
{
    signal(8, handler); // 捕捉8号信号
    int a = 10;
    a /= 0;
    return 0;
}

我们捕捉信号执行的自定义函数没有循环,为什么在结果中会循环打印呢?

当发生除0错误时,CPU内部的状态寄存器(硬件资源)中的溢出标记位会置为1,此时OS就会检测到,并把其解释为kill(targetprocess, SIGFPE)函数调用,就会终止进程,但是我们将SIGFPE进行捕捉之后去执行对应的自定义方法,并没有终止该进程,所以CPU会一直调度该进程,当遇到除0异常时又继续执行我们实现的自定义函数。

当发生一些野指针和越界访问时,此时从由虚拟到物理映射时页表中的MMU硬件单元就会出现异常,就会给进程发送指定信号用来终止进程。

④ 通过软件条件产生

在之前的管道部分就说过,管道的读端关闭,如果写端还是继续写入,OS就会向写端发送SIGPIPE信号来终止写端进程,这就是一种通过软件来产生的信号。

我们可以通过alarm函数来给进程设置一个闹钟,也就是告诉OS在指定时间之后向进程发送SIGALRM信号,默认处理动作是终止当前进程。

alarm接口:

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
using namespace std;

void handler(int signo)
{
    while (true)
    {
        std::cout << "这是一个" << signo << "号信号" << std::endl;
        sleep(1);
    }
}
int main()
{
    signal(SIGALRM, handler);
    // 3秒之后发送信号
    alarm(3);

    while (true)
    {
        cout << "running ...., pid: " << getpid() << endl;
        sleep(1);
    }
    return 0;
}

  • 所有用户的行为都是以进程的形式在操作系统中表现的;
  • 操作系统只要把进程调度好,就能完成所有的用户任务;
  • CMOS时钟会周期性的、高频率的向CPU发送时钟中断;
  • 操作系统的执行是基于硬件中断的!  

3. 核心转储(core dump) 

当进程运行异常时,OS会根据异常信息向进程发送对应的信号使进程终止,并且打印的异常信息也很明确,但是我们如何知道异常出现在程序代码的具体的什么位置呢?

当进程运行发生core异常时,OS会将该进程在内存中发生异常的核心上下文数据转储到磁盘中形成一个以该进程pid和core命名的磁盘文件。

使用命令 ulimit -a:查看core文件的大小

使用命令 ulimit -c 大小:修改core文件的大小

在修改完core文件大小之后出现异常时就会转储到磁盘: 

为什么我们使用的Linux云服务器这个转储的动作默认是关闭的呢?

  • ① 因为发成异常之后形成的core文件太大了;
  • ② 如果异常比较多,磁盘被打满,会直接影响服务器的正常运行。

使用core文件:

朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!  

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

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

相关文章

HarmonyOS开发实战( Beta5.0)日历切换案例实践详解

鸿蒙HarmonyOS开发往期必看&#xff1a; HarmonyOS NEXT应用开发性能实践总结 最新版&#xff01;“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门到精通&#xff09; 介绍 本示例介绍使用Swiper实现自定义日历月视图和周视图左右滑…

反编译app

反编译代码步骤&#xff1a; 1.用dex2jar 将apk打成jar&#xff0c;d2j-dex2jar your-app.apk GitHub - pxb1988/dex2jar: Tools to work with android .dex and java .class filesTools to work with android .dex and java .class files - pxb1988/dex2jarhttps://github.co…

注解实现json序列化的时候自动进行数据脱敏

最近在进行开发的时候遇到一个问题&#xff0c;需要对用户信息进行脱敏处理&#xff0c;原有的方式是写一个util类&#xff0c;在需要脱敏的字段查出数据后&#xff0c;显示掉用方法处理后再set回去&#xff0c;觉得这种方式能实现功能&#xff0c;但是不是特别优雅&#xff0c…

机器学习特征分析

机器学习的常规流程 在真正进入机器学习算法之前&#xff0c;数据准备和处理过程会尤为重要&#xff0c;这直接关系到后续模型的效果和最终的业务判决。 数据分析 什么是数据分析 数据分析指对原始数据进行检查、清理、转换及筛选等一系列动作&#xff0c;找到数据对结果的影…

Qwen1.5模型文本分类微调实战教程

大家好啊!今天咱们来聊聊怎么给大语言模型"调教"一下&#xff0c;让它在文本分类这个任务上玩得更溜。具体来说&#xff0c;我们要用Qwen1.5这个模型来做文章。别看这活儿听着高大上&#xff0c;其实做起来也没那么难。跟着我来&#xff0c;保证让你轻松上手! 咱们这…

How to fool AI content detectors?

Add prompt below: Make it sound like a tweed jacket wearing professor taking to a group of 20 years old students. Vary the sentences length. Make it persoanl, add a touch of humor. Make the blog post sound unique when compared to Other blog posts.

MySQL--库的操作

文章目录 1.创建数据库2.创建数据库案例3.字符集和校验规则3.1默认字符集3.2默认校验规则3.3查看系统默认字符集以及校验规则3.4查看数据库支持的字符3.5查看数据库支持的字符集校验规则3.6校验规则对数据库的影响不区分大小写查询&#xff1a;排序结果&#xff1a;区分大小写查…

BFS广度优先搜索和DFS深度优先搜索解决迷宫问题

前言 BFS广度优先搜索和DFS深度优先搜索解决迷宫问题 迷宫问题 原题目&#xff1a;迷宫由n行m列的单元格组成(n,m都小于等于50)&#xff0c;每个单元格要吗是空地要吗是障碍物。现在请你找到一条从起点到终点的最短路径长度。 分析 BFS广度优先搜索 首先我们将起点入队&a…

iOS 18 RC 版本更新,为相机应用引入了“暂停录制视频”功能

苹果公司9月10日正式向全球iPhone用户推送了iOS 18 Release Candidate&#xff08;RC&#xff09;版本。这一版本的发布不仅标志着iOS系统的又一次重大更新&#xff0c;更预示着苹果在提升用户体验、增强隐私保护以及推动AI应用方面的持续努力。 并且此次苹果公司最新推出的 i…

Unity基本操作

API手册 Unity 脚本 APIhttps://docs.unity.cn/cn/2022.3/ScriptReference/index.html 在遇到不懂的方法、想更深入的学习或者是想查看是否有相应的方法实现某项功能&#xff0c;可以在Unity官方这里查看脚本。以Transform为例&#xff0c;可以直接搜索&#xff0c;或者在Unit…

9月12日 QT

//设置图片缩放适应label ui->label->setScaledContents(true); // 在spinbox后方设置$特殊符号 ui->spinBox->setSuffix(" 斤"); //给肉类combobox加入项目 QStringList Meat_List{"请选择&quo…

数据放到GPU上,运行程序卡住检查方法

这个问题一定是要结合具体的代码&#xff0c;下面就自己遇到问题&#xff0c;询问chatGPT后发现问题所在的过程进行记录&#xff0c;当然绝大部分情况下都是batch_size设置太大了&#xff0c;显卡内存不足导致 部分重点代码&#xff1a; 导入模型部分略 #自定义数据集有关类 c…

无人机 PX4 飞控 | EKF2简介与使用方法

无人机 PX4 飞控 | EKF2简介与使用方法 PX4 EKF2简介EKF 的启动ecl EKF 的优缺点缺点优点 运行单个EKF实例运行多个EKF实例 PX4 EKF2简介 PX4是一个流行的开源飞控系统&#xff0c;广泛用于无人机和其他自动驾驶飞行器。EKF2&#xff08;Extended Kalman Filter 2&#xff09;…

IEEE 802.11a OFDM系统的仿真(续)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第九章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; clear all %%%%%%%参数设计部分%%%%%%%Nsp52;%系统子载波数&#xff08;不包括直流载波&#xff09; Nfft64;%FFT长度 Ncp16;…

ppt文档怎么转换成pdf?快来试试这几种转换方法!

ppt文档怎么转换成pdf&#xff1f;在日常工作与学习的广阔舞台上&#xff0c;PPT&#xff0c;这一演示文稿的常青树&#xff0c;无疑是表达创意、传递信息的重要工具&#xff0c;然而&#xff0c;正如每枚硬币都有其两面&#xff0c;PPT在带来便捷的同时&#xff0c;也显露出一…

js | TypeError: Cannot read properties of null (reading ‘indexOf’) 【解决】

js | TypeError: Cannot read properties of null (reading ‘indexOf’) 【解决】 描述 概述 在前端开发中&#xff0c;遇到TypeError: Cannot read properties of null (reading indexOf)这类错误并不罕见。这个错误通常表明你试图在一个null值上调用indexOf方法&#xff0c…

Linux基础---05输入输出重定向

一.输出重定向符号> 操作1 > 文件 &#xff1a;将操作1的结果覆盖到文件里&#xff0c;并且此文件之前的数据全部清空。 操作2 >>文件&#xff1a;将操作2的结果追加到文件里&#xff0c;原文件的内容不会被清空。 操作3 1>right.txt 2>wrong.txt:操作3的返…

C 盘突然爆满,罪魁祸首竟然是 ...... !

今天打开电脑的时候突然发现 C 盘进度条变红了&#xff0c;这很不正常&#xff01; 做软件开发的应该都会经常在各种磁盘中查找文件和资料&#xff0c;也就会频繁打开 此电脑 窗口&#xff0c;因此即使不是刻意去观察各个磁盘的容量&#xff0c;也会时不时瞟一眼每个盘的占用条…

Java特殊文件xml—利用Dom4J解析xml文件(完整详解,附有代码+案例)

文章目录 三十.特殊文件30.1 xml概述30.1 xml文件30.2 Dom4J解析xml30.2.1 案列130.2.2 案例2 三十.特殊文件 30.1 xml概述 可扩展标记语言 可扩展&#xff1a;标签名字可以自己定义 优点&#xff1a;易于阅读&#xff0c;可以配置成组出现的数据 缺点&#xff1a;解析比较复…

对称矩阵的压缩存储

1.给自己出题&#xff1a;自己动手创造&#xff0c;画一个5行5列的对称矩阵 2.画图&#xff1a;按“行优先”压缩存储上述矩阵&#xff0c;画出一维数组的样子 3.简答&#xff1a;写出元素 i,j 与 数组下标之间的对应关系 4.画图&#xff1a;按“列优先”压缩存储上述矩阵&a…