【Linux】进程信号之信号的保存

news2024/9/29 13:21:23

进程信号 二

  • 一、信号的保存
    • 1、信号其他相关常见概念
    • 2、信号在内核中表示
    • 3、系统内核中信号集
      • sigset_t类型介绍
  • 二、信号集操作函数
    • 1、sigset_t 类型的操作函数
    • 2、关于block表的系统调用
    • 3、关于pending表的系统调用
  • 三、结语

一、信号的保存

1、信号其他相关常见概念

  • 实际执行信号的处理动作称为信号递达(Delivery)
  • 信号从产生到递达之间的状态,称为信号未决(Pending)

进程可以选择阻塞 (Block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。

注意:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作

2、信号在内核中表示

信号在内核中的表示示意图:
在这里插入图片描述

在操作系统内核中有三张表,两张是位图结构(blockpending),一张是函数指针数组结构。

  • block表:该位图结构里面的对应位置的比特位是否为1,代表了该信号是否被阻塞。

  • pending表:该位图结构里面的对应位置的比特位是否为1,代表了该信号是否是未决状态。

  • handler表:该表里面存放的是函数指针,对应下标里面的函数指针表示收到该信号要调用的函数是哪一个。
    (整个三张表里面,数据在逻辑上是横向传递的)

信号里面的SIG_DFL表示的是执行默认动作,SIG_IGN表示的是执行忽略动作。它们的定义如下:

在这里插入图片描述

以前我们使用的signal函数的原理,就是修改了handler表里面对应位置的函数指针。

解释说明:

  • 每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例子中,SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。

  • SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。

  • SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler


如果在进程解除对某信号的阻塞之前,这种信号产生过多次,将如何处理?

POSIX.1允许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。


3、系统内核中信号集

从信号在内核中的表示示意图来看:每个信号只有一个比特位的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。

因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型的本质是一个位图结构,它可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。

sigset_t类型介绍

sigset_tLinux操作系统提供给我们的一种数据类型,其底层封装的是一个long类型的数组,我们使用这个数组里面的每一个比特位去表示相关的信息。

在这里插入图片描述

二、信号集操作函数

1、sigset_t 类型的操作函数

sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量,而不应该直接操作它的内部数据。

在这里插入图片描述

  • 函数sigemptyset初始化 set 所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。

  • 函数sigfillset初始化 set 所指向的信号集,使其中所有信号的对应bit置位1,表示 该信号集的有效信号包括系统支持的所有信号。

  • 函数sigaddset是将 set 所指向的信号集里面信号signum对应的比特位置为1

  • 函数sigdelset是将 set 所指向的信号集里面信号signum对应的比特位置为0

  • sigismember是一个布尔函数,用于判断一个信号集 set 中是否包含signum信号,若包含则返回1,不包含则返回0,出错返回-1。

  • 注意,在使用sigset_ t类型的变量之前,一定要调用sigemptysetsigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddsetsigdelset在该信号集中添加或删除某种有效信号。

  • 这四个函数都是成功返回0,出错返回-1

2、关于block表的系统调用

sigprocmask调用函数可以读取或更改进程的信号屏蔽字(阻塞信号集)。

在这里插入图片描述

  • 参数

  • 第一个参数是一个标记位,它有下面三个选项可以选择:
    (假设当前的信号屏蔽字为mask)

参数功能
SIG_BLOCKset包含了我们希望添加到当前信号屏蔽字的信号,相当于mask = mask | set
SIG_UNBLOCKset包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set
SIG_SETMASK设置当前信号屏蔽字为set所指向的值,相当于mask=set
  • 第二个参数是一个信号集。

  • 第三个信号是一个输出型参数,系统在给block信号集设置新的信号集时,会将老的信号集的内容提取出来将拷贝到oldset里面。

  • 返回值:如果调用成功就返回0,如果调用失败返回-1,错误码被设置。

对于被阻塞的信号,如果阻塞解除,则会被立即递达,所以如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。

下面我们用代码演示证明我们上面的理论,下面的代码意思是我们先对2号信号进行屏蔽,然后打印老的信号屏蔽字,再然后我们打印当前进程的信号屏蔽字,在打印当前进程的信号屏蔽字的时候我们在键盘按下Ctrl + C观察进程是否会退出,如果不退出说明当前信号确实被屏蔽了,最后5s过后恢复原来的信号,2号信号应该被立即递达然后进程退出。

#include <iostream>
#include <signal.h>
#include <unistd.h>


// 打印sigset_t结构
void Printset(sigset_t* set)
{
    for (int i = 1; i <= 31;i++)
    {
        if (sigismember(set, i))
        {
            std::cout << "1";
        }
        else
        {
            std::cout << "0";
        }
    }
}

int main()
{
    // 变量的初始化
    int count = 0;
    sigset_t set, oset;
    sigemptyset(&set);
    sigemptyset(&oset);

    // 设置当前进程的信号屏蔽字
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_SETMASK, &set, &oset);

    // 打印出老的信号屏蔽字
    std::cout << "老的信号屏蔽字是:";
    Printset(&oset);
    std::cout << std::endl;

    while (true)
    {
        std::cout << "目前信号屏蔽字是:";
        Printset(&set);
        std::cout << std::endl;
       

        if (count++ == 5)
        {
            // 恢复原来的信号屏蔽字
            std::cout << "恢复原来的信号屏蔽字" << std::endl;
            sigprocmask(SIG_SETMASK, &oset, &set);
        }
        sleep(1);
    }
    return 0;
}

运行结果如图所示:结果符合我们的预期!

在这里插入图片描述

3、关于pending表的系统调用

对于pending表我们无法修改,只能通过系统调用进行查看。

在这里插入图片描述

sigpending此函数很简单,此函数会读取当前进程的未决信号集,通过set参数传出,调用成功则返回0,出错则返回-1。

下面我们写一个样例继续验证我们上面的原理:我们先屏蔽2号信号,然后打印当前进程的未决信号集,在最初的时候由于进程没有收到信号,我们应该看到的是全零,再然后我们向进程发送一个2号信号,由于2号信号被阻塞,所以当前进程的未决信号集应该是第二个比特位为1,其他为全0。

#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>

// 打印sigset_t结构
void Printset(sigset_t* set)
{
    for (int i = 1; i <= 31;i++)
    {
        if (sigismember(set, i))
        {
            std::cout << "1";
        }
        else
        {
            std::cout << "0";
        }
    }
}

int main()
{
    // 变量的初始化
    int count = 0;
    sigset_t set, oset, pending;
    sigemptyset(&set);
    sigemptyset(&oset);

    // 设置当前进程的信号屏蔽字
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_SETMASK, &set, &oset);
    
    while (true)
    {
        // 打印未决信号集
        sigpending(&pending);
        std::cout << "目前的未决信号集是:";
        Printset(&pending);
        std::cout << std::endl;

        if (count++ == 5)
        {
            // 恢复原来的信号屏蔽字
            std::cout << "恢复原来的信号屏蔽字" << std::endl;
            sigprocmask(SIG_SETMASK, &oset, &set);
        }
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

三、结语

本章讲述的是进程信号的保存,信号的保存概念偏多,实际操作偏少,所以对信号的保存要好好理解操作系统内核中block pending handler表。

下一章我们继续深入理解进程信号的处理,继续提升我们对于信号的理解。当然如果本篇文章有错误或不足的地方,欢迎评论或私信讨论!那么我们下期见,byebye!

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

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

相关文章

1、vscode+cmake c++环境配置

文章目录 1、安装2、开发环境 关于vscode c环境的配置&#xff0c;应该有两种一种是vscodec/c插件&#xff0c;另一种是vscodecmake插件&#xff0c;第一种没太多用过&#xff0c;感觉就像python那样&#xff0c;要写相关配置文件&#xff0c;有自己的一套规则&#xff1b;另一…

【雕爷学编程】Arduino动手做(155)---2262/2272四键无线遥控套件模块

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

ISO接口隔离

IIC为例 为什么需要隔离—隔离电路 隔离电性干扰&#xff0c;增强抗干扰能力&#xff0c;保护隔离总线iic确保系统的稳定型和可靠性。【通过我们强大的I2C缓冲转换器、I/O扩展器和交换机组合&#xff0c;简化您的I2C总线并减少通信错误。这些器件具有宽电压范围和小型工业标准…

手写操作系统--读写硬盘操作

以下图片均来自王道考研视频我们先来看看硬盘的结构&#xff1a; 这是物理图上的磁盘构造。 一个盘片被分成一个个的磁道。 在划分一下就会出现我们的扇区&#xff0c;每个扇区的大小是固定的&#xff0c;一般来说是512个字节。最内侧的扇区面积小&#xff0c;因此数据密度就密…

c++11 标准模板(STL)(std::basic_istream)(一)

定义于头文件 <istream> template< class CharT, class Traits std::char_traits<CharT> > class basic_istream : virtual public std::basic_ios<CharT, Traits> 类模板 basic_istream 提供字符流上的高层输入支持。受支持操作包含带格式…

C#核心知识回顾——11.各数据集合的汇总区分、委托、事件、匿名函数

变量: 无符号 byte正8位 ushort正16位 uint正32位 ulong正64位 有符号 sbyte8位 short16位 int32位 long64位 浮点数 float double decimal 特殊 char bool string 复杂数据容器: 枚举enum 结构体struct 数组(一维、二维、交错) [] [,] [][] 类 数据集合&#xff1a;…

ChatGPT 提示词设置

提示词 Prompt&#xff08;提示词&#xff09;&#xff1a;当我们询问GPT时&#xff0c;发送的消息就是Prompt。 通过给出合适的Prompt&#xff0c;可以让GPT了解我们的想法&#xff0c;在根据我们的想法做出更加合适的判断&#xff0c;帮助我们完成任务&#xff0c;提高效率。…

Oracle存储过程的使用DEMO(一)

文章目录 Oracle存储过程的使用DEMO&#xff08;一&#xff09;1. Oracle中块的使用2. IF使用2.1 IF...ELSE...2.2 IF嵌套 3. CASE...WHEN...4. LOOP5. WHILE6. FOR Oracle存储过程的使用DEMO&#xff08;一&#xff09; 1. Oracle中块的使用 DECLAREI NUMBER; BEGINSELECT EM…

Obfuscar的使用

1、在程序中nuget安装Obfuscar 2、在工程中新建Obfuscar.xml文件&#xff0c;内容如下 <?xml version1.0?> <Obfuscator><!-- 输入的工作路径&#xff0c;采用如约定的 Windows 下的路径表示法&#xff0c;如以下表示当前工作路径 --><!-- 推荐使用当前…

【Spring】项目创建和使用

一、Spring 的概念 Spring : 包含众多工具方法的 IoC 容器。 Spring 的核心 &#xff1a;IoC &#xff08;控制反转&#xff09;&#xff0c; DI (依赖注入)。 loC &#xff08;Inversion of Control&#xff09;翻译成中文就是 “控制反转” 的意思&#xff0c;控制反转一种…

嵌入式QT- QT使用MQTT

目录 一、MQTT介绍 二、MQTT概念 2.1 订阅(Subscribtion) 2.2 会话&#xff08;Session&#xff09; 2.3 主题名&#xff08;Topic Name&#xff09; 2.4 主题筛选器&#xff08;Topic Filter&#xff09; 2.5 消息订阅 三、MQTT中的角色 3.1 客户端 3.2 服务器 四、X86平…

2.1.cuda驱动API-概述

目录 前言1. Driver API概述总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记 本次课程学习精简 CUDA 教程-Driver API 概述 课程大纲可看下…

【UE】点击场景中的物体生成介绍标签

效果 步骤 首先创建一个控件蓝图添加如下控件 给水平框控件添加了一段动画&#xff0c;让该控件显示2秒钟&#xff0c;然后在2~3秒间位置上移并且不透明度减少 在图表中播放动画&#xff0c;延迟3秒后移除控件蓝图 在玩家控制的Pawn中添加如下节点 首先由“由通道检测线条”节…

基于Swing的校园管理系统

1 引言 1.1项目背景 我校积极举办组织学生参加各级各种科技、文艺、体育等校园文化活动&#xff0c;寓思想品德教育于生动活泼、形象具体的校园文化活动中。由于学校各级通讯不太方便&#xff0c;活动筹备过程中&#xff0c;无论是活动参与者的报名、观众的报名还是组织者的…

Image Sensor的FSIN/VSYNC

本文介绍Image Sensor的FSIN/VSYNC。 产品开发过程(比如3D成像)中&#xff0c;有时会遇到需要2个及以上的Image Sensor同步采集&#xff0c;因此&#xff0c;Image Sensor厂家对于他们的产品都提供了同步功能&#xff0c;也就是我们经常所见的FSIN/VSYNC(OV),XVS(Sony IMX3系列…

飞行动力学 - 第6节-part1-喷气式飞机的航时及等高航程 之 基础点摘要

飞行动力学 - 第6节-part1-喷气式飞机的航时及等高航程 之 基础点摘要 1. 续航性能2. 巡航受力运动方程3. 喷气式飞机3.1 航时3.2 航程3.3 等高巡航 4. 参考资料 1. 续航性能 耗油率航程航时 2. 巡航受力运动方程 6个方程表达式来进行表达&#xff1a; 3. 喷气式飞机 3.1 …

chatgpt api + function calling + 高德天气API + google custom search【联谷歌,联高德】

OpenAI 发布几个重磅更新 1、 开放 16k 上下文的 GPT-3.5-Turbo 模型&#xff08;gpt-3.5-turbo-16k&#xff09;&#xff0c;是目前的4倍 2、 新的 GPT-4 和 3.5 Turbo 模型 3、Chat Completions API 中的新增加函数调用功能 &#xff08;实时获取网络数据成为可能&#xff0…

SpringBoot2+Vue2实战(十二)springboot一对一,一对多查询

新建数据库表 Course Data TableName("t_course") public class Course implements Serializable {private static final long serialVersionUID 1L;/*** id*/TableId(value "id", type IdType.AUTO)private Integer id;/*** 课程名称*/private String…

如何成为微软MVP?

对一个普通的开发人员来说&#xff0c;最大的认可就是得到微软官方的MVP 认证了&#xff0c;是一份对技术人的荣誉证书。 微软的MVP是相对公平公正的&#xff0c;只要你热爱技术&#xff0c;热爱分享&#xff0c;在一定的领域里有足够的深度&#xff0c;就会得到微软官方的认证…

【沐风老师】3dMax使用Dreamscape插件创建漂亮的日落场景教程

在本教程中,您将学习如何利用3dMax和DreamScape在平静的海面上创造一个美丽的日落效果。DreamScape是3dMax的一套复杂的插件,可以让你创造和呈现现实的景观、海景、天空、云层、户外照明等等。 【最后效果预览】 步骤1&#xff1a;首先,要用DreamScape来呈现一个场景,你需要创…