【Linux】进程信号——信号保存和信号捕捉

在这里插入图片描述

文章目录

  • 信号保存
    • 信号相关的概念
    • 信号是如何保存的呢?
    • 有关信号保存的系统调用
      • sigprocmask
      • 信号的增删查改
      • 查看pending表
      • 验证接口
  • 信号捕捉
      • 用户态与内核态
      • 信号捕捉流程
  • 总结

信号保存

信号相关的概念

信号递达:指 操作系统 将一个信号(Signal)从内核传递到目标进程 的过程。它是 信号处理机制 中的关键步骤。
信号未决:信号从产生到递达之间的状态
信号阻塞 进程或线程可以暂时屏蔽某些信号,使它们在阻塞期间不会递达和处理。一旦解除阻塞,信号会被递达并处理。

被阻塞的信号将保持未决状态,直到进程解除对此信号的阻塞,才能执行递达的动作。

注意:阻塞信号和忽略信号不同,阻塞信号表示信号没有递达,但是忽略信号表示信号已经抵达了,但是我们的处理方式是忽略处理。

信号是如何保存的呢?

在task_struct中有三张表,分别是下面三张:
在这里插入图片描述
前两张表是位图,第三张表是函数指针表。
我们从左到右说起:
第一张表是位图,比特位的位置是信号编号,比特位的含义是是否阻塞信号,1表示阻塞当前编号的信号,0表示为阻塞当前信号。
第二张表也是位图,比特位的位置是信号编号,比特位的含义是是否收到信号,1表示收到信号,0表示未收到信号。
第三张表是函数指针表,表示每个信号对应方法,当收到信号之后,我们将拿着信号编号,然后在handler表中查找对应信号的方法。
在这里插入图片描述
内核中三个表的结构,如上图。

有关信号保存的系统调用

sigprocmask

在这里插入图片描述
这个函数的作用是获取或者设置当前进程的block表。
第一个参数表示我们用这个函数干嘛,有以下三种选项:
在这里插入图片描述
三种选项的作用也有批注。
在讲第二个参数之前我们先讲讲sigset_t这个类型:
sigset_t是一个用于表示 信号集合的数据类型,定义在 <signal.h> 头文件中。它通常用于 阻塞信号、解除信号阻塞 和 检查信号 等操作。
第二个参数是新的信号集,是我们修改后的信号集,而第三个参数是旧的信号集,是修改之前的信号集,方便我们修改之后方便恢复。

信号的增删查改

在这里插入图片描述
上面五个函数是增删查改,第一个函数是将一个信号集置为零,第二个函数是将信号集全部设置为1,第三个函数是添加新的信号到信号集当中,第四个函数表示在信号集中删除指定信号,第五个函数是在指定信号集中查找指定信号。

查看pending表

在这里插入图片描述
这个函数很简单,参数是输出参数,可以将当前进程的pending表输出出来,但是为什么没有设置pending表的呢?因为产生信号的方式有很多种,我们在上一章中讲到过,我们拿一个作为例子,比如说命令kill就可以产生信号。

我们讲完上面的接口,我们来写一个简单的代码,来验证一下,这些接口是否有屏蔽信号的功能。

验证接口

代码

#include <iostream>
#include <signal.h>
using namespace std;

void Printf(const sigset_t& pending)
{
    for(int i = 31;i > 0;i--)
    {
        if(sigismember(&pending,i) == 1)
        {
            cout<<1;
        }
        else cout<<0;
    }
    cout<<endl;
}

int main()
{
    sigset_t block,oblock;

    //重置两个block表
    sigemptyset(&block);
    sigemptyset(&oblock);

    //设置屏蔽信号
    sigaddset(&block,2);

    //将信号设置进内核
    sigprocmask(SIG_BLOCK,&block,&oblock);

    sigset_t pending;
    while(true)
    {
        //打印pending表
        sigpending(&pending);
        Printf(pending);
        sleep(1);
    }
    return 0;
}

运行结果

在这里插入图片描述
为什么当我们输入ctrl+c的时候,为什么在pending表中会一直存在2号信号呢?因为我们之前做了阻塞,当收到2号信号的时候,将其阻塞,所以pending表中会一直受到信号。所以如何解决这种情况呢?
我们可以定义一个计数器,当计数器走到10的时候将2号信号进入递达状态。
代码:

#include <iostream>
#include <signal.h>
using namespace std;

void Printf(const sigset_t& pending)
{
    for(int i = 31;i > 0;i--)
    {
        if(sigismember(&pending,i) == 1)
        {
            cout<<1;
        }
        else cout<<0;
    }
    cout<<endl;
}

int main()
{
    sigset_t block,oblock;

    //重置两个block表
    sigemptyset(&block);
    sigemptyset(&oblock);

    //设置屏蔽信号
    sigaddset(&block,2);

    //将信号设置进内核
    sigprocmask(SIG_BLOCK,&block,&oblock);

    sigset_t pending;
    int count = 0;
    while(true)
    {
        //打印pending表
        sigpending(&pending);
        Printf(pending);
        if(count == 10)
        {
            sigprocmask(SIG_SETMASK,&oblock,nullptr);
            cout<<"Unblock signal"<<endl;
        }
        count++;
        sleep(1);
    }
    return 0;
}

结果
在这里插入图片描述
因为ctrl+c默认处理方式就是结束进程所以这里,我们看到的是结束,没有看到pending表的变化,我们加入signal函数进行信号捕捉,进行我们的自定义方法,不结束进程,查看pending表的变化状态:
在这里插入图片描述
可以看见,当信号从屏蔽字中去除的时候,执行自定义方法,然后pending表中2号信号消失。

信号捕捉

用户态与内核态

在操作系统中,CPU 主要运行在 用户态(User Mode)内核态(Kernel Mode)。这两种模式是 操作系统的特权级别,用于保护系统的安全和稳定性。

  • 用户态(User Mode):

    • 权限受限,不能直接访问硬件(如磁盘、网络、内存管理等)。
    • 运行用户进程(如应用程序)。
    • 只能通过系统调用请求内核提供服务(比如 read()write()open())。
  • 内核态(Kernel Mode):

    • 最高权限,可以直接访问所有资源(如 CPU、内存、I/O 设备)。
    • 运行操作系统内核代码(进程管理、文件系统、设备驱动等)。
    • 可以直接操作硬件,比如修改页表、控制设备中断。

CPU 通过 模式位(mode bit) 来区分这两种状态:

  • 0 表示 内核态(特权模式)。
  • 1 表示 用户态(受限模式)。

信号捕捉流程

在这里插入图片描述
之前讲到处理信号是在合适的时候处理的,什么是合适的时候呢?

进程从内核态切换到用户态的时候,操作系统检测当前进程的pending表&&block表,决定是否处理handler表处理信号

假如我们写了一个代码,当我们进行某些系统调用的时候,会出现中断,中断之后会进入内核态,当进入内核态之后,会处理当前进程中可以传递信号,如果信号的处理方式是自定义处理方式会直接返回用户态调用自定义方法,处理完后返回内核态,从上次中断的地方继续执行。

总结

通过本文的探讨,我们深入了解了Linux中进程信号的保存和捕捉机制。信号作为进程间通信的一种重要方式,能够有效地处理异步事件和异常情况。我们学习了信号的基本概念、信号的保存方式(如信号掩码和未决信号集),以及如何通过信号处理函数来捕捉和处理信号。

在实际应用中,合理地使用信号机制可以大大提高程序的健壮性和响应能力。然而,信号处理也需要注意一些细节,例如信号处理函数的可重入性、信号竞争条件的避免等。掌握这些知识点,能够帮助我们在编写多进程、多线程程序时更加得心应手。

希望本文的内容能够帮助你更好地理解Linux信号机制,并在实际开发中灵活运用。如果你有任何问题或建议,欢迎在评论区留言讨论!

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

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

相关文章

【FL0090】基于SSM和微信小程序的球馆预约系统

&#x1f9d1;‍&#x1f4bb;博主介绍&#x1f9d1;‍&#x1f4bb; 全网粉丝10W,CSDN全栈领域优质创作者&#xff0c;博客之星、掘金/知乎/b站/华为云/阿里云等平台优质作者、专注于Java、小程序/APP、python、大数据等技术领域和毕业项目实战&#xff0c;以及程序定制化开发…

因子分析讲解

一、定义 因子分析&#xff08;Factor Analysis&#xff09;是一种常用于多变量统计分析的方法&#xff0c;主要用于数据降维、识别潜在的结构、理解变量间的关系。它通过将一组观察变量&#xff08;通常是高度相关的变量&#xff09;转化为一组较少的、互不相关的因子&#x…

从 JVM 源码(HotSpot)看 synchronized 原理

大家好&#xff0c;我是此林。 不知道大家有没有这样一种感觉&#xff0c;网上对于一些 Java 框架和类的原理实现众说纷纭&#xff0c;看了总是不明白、不透彻。常常会想&#xff1a;真的是这样吗&#xff1f; 今天我们就从 HotSpot 源码级别去看 synchronized 的实现原理。全…

DeepSeek搭配Excel,制作自定义按钮,实现办公自动化!

今天跟大家分享下我们如何将DeepSeek生成的VBA代码&#xff0c;做成按钮&#xff0c;将其永久保存在我们的Excel表格中&#xff0c;下次遇到类似的问题&#xff0c;直接在Excel中点击按钮&#xff0c;就能10秒搞定&#xff0c;操作也非常的简单. 一、代码准备 代码可以直接询问…

Metal学习笔记十一:贴图和材质

在上一章中&#xff0c;您设置了一个简单的 Phong 光照模型。近年来&#xff0c;研究人员在基于物理的渲染 &#xff08;PBR&#xff09; 方面取得了长足的进步。PBR 尝试准确表示真实世界的着色&#xff0c;真实世界中离开表面的光量小于表面接收的光量。在现实世界中&#xf…

zabbix“专家坐诊”第277期问答

在线答疑:乐维社区 问题一 Q&#xff1a;这个怎么解决呢&#xff1f; A&#xff1a;缺少这个依赖。 Q&#xff1a;就一直装不上。 A&#xff1a;装 zabbix-agent2-7.0.0-releasel.el7.x86 64 需要前面提示的那个依赖才可以装。 问题二 Q&#xff1a;大佬&#xff0c;如果agen…

让单链表不再云里雾里

一日不见&#xff0c;如三月兮&#xff01;接下来与我一起创建单链表吧&#xff01; 目录 单链表的结构&#xff1a; 创建单链表&#xff1a; 增加结点&#xff1a; 插入结点&#xff1a; 删除结点&#xff1a; 打印单链表&#xff1a; 单链表查找&#xff1a; 单链表…

图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image

图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image 文章目录 图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image主要创新点模型架构图生成器生成器源码 判别器判别器源码 损失函数需要源码讲解的私信我 S…

指纹细节提取(Matlab实现)

指纹细节提取概述指纹作为人体生物特征识别领域中应用最为广泛的特征之一&#xff0c;具有独特性、稳定性和便利性。指纹细节特征对于指纹识别的准确性和可靠性起着关键作用。指纹细节提取&#xff0c;即从指纹图像中精确地提取出能够表征指纹唯一性的关键特征点&#xff0c;是…

泵吸式激光可燃气体监测仪:快速精准守护燃气管网安全

在城市化进程加速的今天&#xff0c;燃气泄漏、地下管网老化等问题时刻威胁着城市安全。如何实现精准、高效的可燃气体监测&#xff0c;守护“城市生命线”&#xff0c;成为新型基础设施建设的核心课题。泵吸式激光可燃气体监测仪&#xff0c;以创新科技赋能安全监测&#xff0…

HTML label 标签使用

点击 <label> 标签通常会使与之关联的表单控件获得焦点或被激活。 通过正确使用 <label> 标签&#xff0c;可以使表单更加友好和易于使用&#xff0c;同时提高整体的可访问性。 基本用法 <label> 标签通过 for 属性与 id 为 username 的 <input> 元素…

数字万用表的使用教程

福禄克经济型数字万用表前面板按键功能介绍示意图 1. 万用表简单介绍 万用表是一种带有整流器的、可以测量交、直流电流、电压及电阻等多种电学参量的磁电式仪表。分为数字万用表&#xff0c;钳形万用表&#xff0c; &#xff08;1&#xff09;表笔分为红、黑二只。使用时黑色…

Python 爬取唐诗宋词三百首

你可以使用 requests 和 BeautifulSoup 来爬取《唐诗三百首》和《宋词三百首》的数据。以下是一个基本的 Python 爬虫示例&#xff0c;它从 中华诗词网 或类似的网站获取数据并保存为 JSON 文件。 import requests from bs4 import BeautifulSoup import json import time# 爬取…

2025年AI PPT工具精选:让演示文稿更智能、更高效

&#x1f4a1; 做PPT太难&#xff1f;没灵感&#xff1f;排版不好看&#xff1f;别怕&#xff0c;AI已经帮你安排好了&#xff01; 想知道2025年最值得推荐的AI PPT工具是哪款&#xff1f;答案就是——秒出PPT&#xff01;&#x1f680; 不仅能一键生成PPT&#xff0c;还能自…

qt-C++笔记之ubuntu22.04源码安装Qt6.8.2

qt-C笔记之ubuntu22.04源码安装Qt6.8.2 code review! 文章目录 qt-C笔记之ubuntu22.04源码安装Qt6.8.21.作者环境&#xff1a;ubuntu22.04、cmake202.安装3.关联已安装的 Qt6 到 Qt Creator4.附&#xff1a;ubuntu18.0的处理&#xff0c;可尝试&#xff0c;作者没有遇到这个问题…

单例模式(线程案例)

单例模式可以分为两种&#xff1a;1.饿汉模式 2.懒汉模式 一.饿汉模式 //饿汉模式&#x1f447; class MySingleTon{//因为这是一个静态成员变量&#xff0c;在类加载的时候&#xff0c;就创建了private static MySingleTon mySingleTon new MySingleTon();//创建一个静…

基于Matlab的多目标粒子群优化

在复杂系统的设计、决策与优化问题中&#xff0c;常常需要同时兼顾多个相互冲突的目标&#xff0c;多目标粒子群优化&#xff08;MOPSO&#xff09;算法应运而生&#xff0c;作为群体智能优化算法家族中的重要成员&#xff0c;它为解决此类棘手难题提供了高效且富有创新性的解决…

(2025年)工会考试该如何高效备考?有学习方法吗?

工会考试备考文章 工会考试高效备考指南 工会在维护职工权益、促进企业和谐发展中扮演着重要角色&#xff0c;工会考试则是选拔优秀工会工作者的关键途径。面对工会考试涉及的法律法规、组织管理以及维权服务等多方面知识&#xff0c;掌握科学备考方法是成功的关键。 法律法规是…

《机器学习数学基础》补充资料:向量范数

《机器学习数学基础》第1章1.5.3节介绍了向量范数的基本定义。 本文在上述基础上&#xff0c;介绍向量范数的有关性质。 注意&#xff1a; 以下均在欧几里得空间讨论&#xff0c;即欧氏范数。 1. 性质 实&#xff08;或复&#xff09;向量 x \pmb{x} x &#xff0c;范数 ∥…

Unity NGUI新手向几个问题记录

1.点Button没反应 制作Button组件时&#xff0c;不光要挂载Button脚本&#xff0c;还有挂载BoxCollider BoxCollider 接收事件 2.Button点击事件的增加与删除 使用.onClick.add增加事件&#xff0c;使用.onClick.Remove,.onClick.RemoveAt,onClick.RemoveRang,onClick.Clear移…