_Linux 进程信号-信号保存篇

news2024/11/28 4:43:05

文章目录

  • 前言
  • 阻塞信号
    • 1. 信号常见概念
    • 2. 在内核中的表示
      • 信号处理过程
    • 3. sigset_t
    • 4. 信号集操作函数
      • sigprocmask
      • sigpending
    • 5. 测试与验证
      • 实验一
      • 实验二
      • 实验三

前言

上篇文章(链接: _Linux 进程信号-基础篇)我们了解了信号的基础概念以及信号如何发送的。

阻塞信号

1. 信号常见概念

  • 实际执行信号的处理动作称为信号递达(Delivery)
  • 信号从产生到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (Block )某个信号。
  • 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
  • 注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

2. 在内核中的表示

在这里插入图片描述
上面一张图;我们知道信号OS需要三张位图才能对信号做到准确执行。

  • block位图:表示信号是否被阻塞
  • pending位图:表示信号未被处理,信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。
  • handler:表示递达;当信号未阻塞也未产生过(信号未被捕捉),当它递达时执行默认处理动作;就是跟我们上一篇文章学习到的信号捕捉的 函数—signal;我们知道它捕捉成功并不是立即生效。也就是信号捕捉其实就是把原来要执行的默认改成自定义动作。handler函数指针数组的下表代表的是信号的编号;里面内容((int)handler[signal]==0或1)
    • 0:代表执行默认动作
    • 1:代表执行忽略动作。

信号处理过程

  • 一个信号处理过程(pending -> block -> handler)
  • 当一个信号来时,先在pending位图中,由0置1;然后在在block位图中查找该信号是否被阻塞;
      1. 阻塞时信号就无法递达
      1. 未被阻塞时信号可以递达

3. sigset_t

从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。下一节将详细介绍信号集的各种操作。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。

4. 信号集操作函数

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

    #include <signal.h>
    int sigemptyset(sigset_t *set);
    int sigfillset(sigset_t *set);
    int sigaddset (sigset_t *set, int signo);
    int sigdelset(sigset_t *set, int signo);
    int sigismember(const sigset_t *set, int signo);
    
  • 函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。

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

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

  • sigismember函数用来测试参数signum 代表的信号是否已加入至参数set信号集里。

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

sigprocmask

  • 调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集);即对应这pcb位图中block(阻塞)那张位图。

    #include <signal.h>
    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    
    • 如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。
    • 如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。
    • 如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。
  • 假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

how的可选值用法说明
SIG_BLOCKset包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask l set
SIG_UNBLOCKset包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于 mask=mask&~set
SIG_SETMASK设置当前信号屏蔽字为set所指向的值,相当于mask=set
  • 如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。

sigpending

#include <signal.h>
int sigpending(sigset_t *set);
读取当前进程的未决信号集,通过set参数传出。
调用成功则返回0,出错则返回-1。

5. 测试与验证

实验一

  • 1.如果我们对所有的信号都进行了自定义捕捉 — 我们是不是就写了一个不会被异常或者用户杀掉的送进程??

    • 答案是:并不是,OS的设计者也考虑了! 例如:9号信号无法被捕捉。
  • 代码 :

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

using namespace std;

void catchSig(int sigNum)
{
    cout << "捕捉到一个信号..."
         << "编号--sig: " << sigNum << endl;
}

int main()
{
    for (int i = 1; i <= 31; ++i)
        signal(i, catchSig);

    while (1)
        sleep(1);
    return 0;
}

在这里插入图片描述

  • 当然了 除了9 号(杀死程序) 还有19 号(暂停程序)都是不可捕捉信号。
  • 实验一结果图如下:
    在这里插入图片描述

实验二

  • 2.如果我们将2号信号block,并且不断的获取并打印当前进程的pending信号集,如果我们突然发送一个2号信号,我们就应该肉眼看到pending信号集中,有一个比特位0置1的过程;20s后我们解除对2号信号的block(阻塞)就有一个比特位1置10的过程。
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <assert.h>

using namespace std;

// 实验二

static void showPending(sigset_t &pending)
{
    for (int i = 1; i <= 31; ++i)
    {
        if (sigismember(&pending, i))
            cout << 1;
        else
            cout << 0;
    }
    cout << endl;
}

static void catchSig(int sigNum)
{
    cout << "捕捉到一个信号..."
         << "编号--sig: " << sigNum << endl;
}

int main()
{
    // 0. 方便测试,捕捉2号信号,不要退出
    signal(2, catchSig);

    // 1. 定义信号集对象
    sigset_t bset, obset;
    sigset_t pending;

    // 2. 信号初始化
    sigemptyset(&bset);
    sigemptyset(&obset);
    sigemptyset(&pending);

    // 3. 添加要屏蔽的信号
    sigaddset(&bset, 2);

    // 4. 设置set到内核中对应的进程内部[默认情况进程不会对任何信号进行block]
    int n = sigprocmask(SIG_BLOCK, &bset, &obset); // 返回屏蔽之前老的信号
    assert(n == 0);
    (void)n;

    cout << "屏蔽2号信号成功..." << endl;
    // 5. 重复打印当前进程的pending信号集
    int count = 0;
    while (true)
    {
        // 5.1 获取当前进程的pending信号集
        sigpending(&pending);
        // 5.2 显示pending信号集中的没有被递达的信号
        showPending(pending);
        sleep(1);
        ++count;
        if (count == 20) // 20s后解除阻塞
        {
            int n = sigprocmask(SIG_UNBLOCK, &bset, &obset); // 返回屏蔽之前老的信号
            assert(n == 0);
            (void)n;
        }
    }

    return 0;
}
  • 实验二结果图如下:
    在这里插入图片描述

实验三

  • 3.如果我们对所有的都进行block(阻塞) — 我们是不是就写了一个不会被异常或者用户杀掉的进程??

  • 答案是:并不是,OS的设计者也考虑了!

  • 代码:

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

using namespace std;

static void showPending(sigset_t &pending)
{
    for (int i = 1; i <= 31; ++i)
    {
        if (sigismember(&pending, i))
            cout << 1;
        else
            cout << 0;
    }
    cout << endl;
}

static void blockSig(int sigNum)
{
    sigset_t bset;
    sigemptyset(&bset);
    sigaddset(&bset, sigNum);
    int n = sigprocmask(SIG_BLOCK, &bset, nullptr);
    assert(n == 0);
    (void)n;
}
// 实验三

int main()
{
    for (int i = 1; i <= 31; ++i)
        blockSig(i);
    sigset_t pending;
    sigemptyset(&pending);
    while (true)
    {
        sigpending(&pending);
        showPending(pending);
        sleep(1);
    }

    return 0;
}
  • 实验二结果图如下:
    在这里插入图片描述

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

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

相关文章

强化学习_06_pytorch-PPO实践(Pendulum-v1)

一、PPO简介 TRPO(Trust Range Policy Optimate)算法每一步更新都需要大量的运算&#xff0c;于是便有其改进版本PPO在2017年被提出。PPO 基于 TRPO 的思想&#xff0c;但是其算法实现更加简单。TRPO 使用泰勒展开近似、共轭梯度、线性搜索等方法直接求解。PPO 的优化目标与 T…

可观测性--数据源

文章目录监控数据来源端上访问应用程序业务监控基础设施可观测性核心概念日志&#xff08;Logging&#xff09;统计指标&#xff08;Metrics&#xff09;链路追踪&#xff08;Tracing&#xff09;三者之间关系监控数据来源 我们一般讲的数据观测&#xff0c;其实观测的就是从发…

【Linux】计算机软硬件体系结构

文章目录冯诺依曼体系结构操作系统(Operator System)什么是操作系统为什么要有操作系统操作系统是怎么实现管理的系统调用接口和库函数总结冯诺依曼体系结构 谈到计算机的硬件结构&#xff0c;第一个想到的必然是经典的冯诺依曼体系结构&#xff1a; 我们常见的计算机&#xf…

在购买低代码产品时,源码是必需的吗?

编者按&#xff1a;企业在采购软件或者平台时&#xff0c;到底需不需要源码&#xff1f;本文分析了源码交付的对于不同规模和情况企业的意义&#xff0c;并介绍了源码交付的低代码平台。关键词&#xff1a;源码交付&#xff0c;可视化设计&#xff0c;私有化部署&#xff0c;多…

数据上线:首届6G智能无线通信系统大赛OPPO赛道评测正式开启

12月26日&#xff0c;首届6G智能无线通信系统大赛——面向小样本条件场景自适应及在线更新需求的无线AI设计赛题已经正式上线&#xff0c;数据集也已经在1月3日正式上线啦&#xff0c;评测同步开启&#xff0c;快来打擂冲榜&#xff01; 文末还将揭晓本赛题专属活动&#xff0…

图像锐化处理之一阶微分算子

图像锐化是通过增强图像的边缘和细节来提高图像的清晰度的操作。这种操作通常用于将模糊或不清晰的图像改进为更清晰的图像。由于微分是对函数局部变化率的一种描述&#xff0c;因此图像锐化算法的实现可基于空间微分。 一阶微分算子 对任意一阶微分的定义必须满足两点&#xf…

采用热电偶温度传感器实现超高精度温度跟踪控制的解决方案

摘要&#xff1a;针对温度跟踪控制中存在热电堆信号小致使控制器温度跟踪控制精度差&#xff0c;以及热电阻形式的温度跟踪控制中需要额外配置惠斯特电桥进行转换的问题&#xff0c;本文提出相应的解决方案。解决方案的核心是采用一个多功能的超高精度PID控制器&#xff0c;具有…

ubuntu18.04安装mysql5.7.32

目录一、下载mysql安装包二、下载依赖三、安装mysql四、导入sql一、下载mysql安装包 下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 下载包 mysql-server_5.7.32-1ubuntu18.04_amd64.deb-bundle.tar 下载后解压&#xff0c;里面包含要安装的deb包 二、…

计算机编码

字符的表示原理 计算机内所有信息都是使用0和1进行表示的。 对于一个短路来说&#xff0c;0代表关&#xff0c;1代表开。那把这些电路组合起来就可以有长串0和1组成的二进制数字&#xff0c;我们对这些数字进行编码和解码&#xff0c;我们就能用它来表示我们想要表示的东西了…

蓝牙模块芯片串口透传的AT指令模式和波特率是什么意思

一、什么是蓝牙串口透传模块的模式 蓝牙串口模块&#xff0c;一般都会有两个模式&#xff0c;即AT指令模式&#xff0c;以及透传模式 1、有的模块&#xff0c;会通过一个GPIO口来选择当前是什么模式&#xff0c;比如将一个IO口拉低则进入透传模式&#xff0c;也就是不再识别A…

element-ui 表格el-table高度不是一个固定值时固定表头

elementui中为表格组件提供了height属性实现固定表头 height可以为数字或者字符串&#xff0c;当为一个数字时表示固定的高度&#xff0c;也可以为百分比等字符串。 当height不是一个固定值时&#xff0c;如期望表格可以填充完页面剩余空间&#xff0c;并且固定表头时&#x…

Mysql之常见可视化管理工具

mysql在日常开发中作为基础软件&#xff0c;对其数据的管理必不可少&#xff0c;除了系统自带的命令行管理工具之外&#xff0c;还有许多其他的图形化管理工具&#xff0c;下面介绍常见的mysql图形化管理工具。 1、Navicat Navicat 是一个桌面版 MySQL 数据库管理和开发工具。…

【Linux操作系统】程序的编译和动静态链接

文章目录一.编译写在前面1.预处理2.编译3.汇编二.(动静态)链接1.动态链接2.静态链接3.静态链接库的下载安装4.windows下动静态库的后缀一.编译 写在前面 编译这整个过程都只是在编译你自己写的代码,直到链接才让你的代码和库的代码关联起来,最终形成可执行程序 源程序到可执行…

靶机测试Os-ByteSec笔记

靶机测试Os-ByteSec笔记 靶机描述 Back to the Top Difficulty : Intermediate Flag : 2 Flag first user And second root Learning : exploit | SMB | Enumration | Stenography | Privilege Escalation Contact … https://www.linkedin.com/in/rahulgehlaut/ This w…

EXSi root密码忘记通过centos7镜像破解

1.安装软碟通UltraISO刻录U盘启动盘 下载阿里云centos7镜像&#xff0c;选择mini的链接&#xff1a;https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-Minimal-2207-02.iso?spma2c6h.25603864.0.0.28f76aeapbXyYT 打开软碟通&#xff0c;打开下载的…

C语言宏定义立即数后缀U的含义

背景 在看开源的相关代码中&#xff0c;会有下面的宏定义用法 #define TEST_VALUE (0xFFFFFFFFU) 其和下面的宏定义区别是什么呢&#xff1f; #define TEST_VALUE (0xFFFFFFFF) 答疑 U表示 unsigned 无符号后缀&#xff0c;关于后缀的表述C99标准有如下定义&…

私有部署V3.8:自建内部应用库和预置应用

2022年12月27日&#xff0c;明道云私有部署V3.8正式发布。除了同步更新明道云SaaS版V7.8的功能以外&#xff0c;V3.8还将应用库功能下放至私有部署&#xff0c;私有部署用户可以自建企业内部应用库&#xff0c;并且给新创建的组织预置应用了。 注意&#xff1a;该功能仅面向明…

CSS知识点精学4-学成项目案例实现

根目录 先写好项目根目录 网站的首页,所有网站的首页都叫index.html,因为服务器找首页都是找index.html 一般网站页面配套的css文件与网站设置为相同的名字 比如index.html搭配index.css 准备工作 首先&#xff0c;我们发现没一个模块都是居中显示的&#xff0c;抓住一个边…

Python压缩模块gzip

文章目录初步认识压缩和解压缩函数初步认识 gzip是用于处理gzip格式的模块&#xff0c;相当于是zlib模块面向文件的一个应用&#xff0c;其最常用的函数为open。 有了open&#xff0c;那就得演示一下文件读写 import gzip with gzip.open(test.txt.gz, wb) as f:f.write(&qu…

Halcon笔记1

一、前言 最近来触碰一下halcon&#xff0c;一直以来作为ai算法工程师&#xff0c;虽然知道halcon&#xff0c;但是一直也没有用过 对于我们用户来说&#xff0c;halcon与opencv的差距主要在下面&#xff1a; &#xff08;1&#xff09;halcon是闭源的&#xff0c;商业的软件…