Linux信号之信号的保存

(。・∀・)ノ゙嗨!你好这里是ky233的主页:这里是ky233的主页,欢迎光临~icon-default.png?t=N7T8https://blog.csdn.net/ky233?type=blog

点个关注不迷路⌯'▾'⌯

目录

一、阻塞信号

1.信号递达、未决、阻塞

 2.内核表示图

3.sigset_t

4.sigpending

5.sigprocmask

二、验证问题

1.问题一

2.问题二

3.问题三


一、阻塞信号

1.信号递达、未决、阻塞

  • 实际执行信号的处理动作称为信号递达(Delivery)。

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

 2.内核表示图

在内核中其实一共有两个位图结构,第二个就是我们的pending位图,也就是OS修改的位图结构,第三个则是代表的信号,是一个函数指针数组,里边存放的是所对应的函数地址

而在handler里面会先判断是否是等0还是1,0则执行默认的动作,1则直接忽略的动作,都不是才会执行我们自己写的动作!

第一个block则代表的是我们的阻塞位图,OS先把对应的信号写入pending里,然后回来查看,block里面是否阻塞,如果阻塞则不进行调用,等到不阻塞时候才回去handler里进行下一步操作!

3.sigset_t

这是一个位图结构,但是不允许用户自己进行位操作,所以OS给我们提供了对应的操作方法

用户可以直接使用该类型,和用内置类型以及自定义类型是没有任何差别的 

每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。 因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号 的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有 效”和“无效”的含义是该信号是否处于未决状态。

总的来说就是用来表示block和pending的

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); 

上面就是OS所提供的五个可以对位图本身修改的接口

  1. 函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有 效信号。
  2. 函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系 统支持的所有信号。
  3. 注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的 状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号
  4. sigismember:最后一个是判定一个信号时候再该信号集之中 

4.sigpending

int sigpending(sigset_t *set)

通过该函数可以获取当前调用进程的pending信号集,也就是把操作系统内核中的数据拿给用户

  • 返回值:成功为0,失败为-1

5.sigprocmask

int sigprocmask(int how,const sigset_t *set,sigset_t *oldset)

检查并更改我们的阻塞信号集

  • 参数一:设定特定的操作
  • 参数二:设定特定的位图
  • 参数三:输出型参数,返回老的信号屏蔽图(阻塞位图block),如果需要的话
  • 返回值:若成功则为0,若出错则为-1

how:

  • SIG_BLOCK:set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set
  • SIG_UNBLOCK:set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set
  • SIG_SETMASK:设置当前信号屏蔽字为set所指向的值,相当于mask=set

二、验证问题

1.问题一

如果我们对所有的信号都进行了自定义不做,我们是不是就写了一个不会被一场或者用户杀掉的进程?

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

void catchSig(int signum)
{
    cout << "获得了一个信号:" << signum << endl;
}

int main()
{
    for (int i = 1; i <= 31; i++)
    {
        signal(i, catchSig);
    }
    while (1)
    {
        sleep(1);
    }
    return 0;
}

 虽然我们看到的好像就是这样,可其实并不是,OS设计者也考虑过,我们的9号信号(SIGKILL)是不可以被捕捉的!

2.问题二

如果我们将二号信号阻塞,并且不断地获取并打印当前进程的pending信号,如果我们突然发送一个二号信号,我们应该肉眼看到pending信号集中,有一个比特位从0变为1

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

int main()
{
    // 定义信号集
    sigset_t bset, obset;
    sigset_t pending;
    // 初始化
    sigemptyset(&bset);
    sigemptyset(&obset);
    sigemptyset(&pending);
    // 添加要进行屏蔽的信号
    sigaddset(&bset, 2);
    // 设置set到内核中
    int n = sigprocmask(SIG_BLOCK, &bset, &obset);
    assert(n == 0);
    cout << "2号信号以阻塞" << endl;
    (void)n;
    // 重复打印当前的pending信号集
    while (1)
    {
        // 获取当前进程的pending信号集
        sigpending(&pending);
        // 显示pending中的没有被递达的信号
        shouPending(pending);
        sleep(1);

    }
    return 0;
}

首先我们看到当前进程的pending位图都是0,这是因为虽然我们阻塞了,但是不代表这个进程收到了2号信号,当我们发完之后,确实如我们所说,有一个比特位由0变1了

 可是如果我们要解除2号信号的阻塞呢?那我们的pending信号集就应该从1变成0!

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

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

int main()
{
    // 定义信号集
    sigset_t bset, obset;
    sigset_t pending;
    // 初始化
    sigemptyset(&bset);
    sigemptyset(&obset);
    sigemptyset(&pending);
    // 添加要进行屏蔽的信号
    sigaddset(&bset, 2);
    // 设置set到内核中
    int n = sigprocmask(SIG_BLOCK, &bset, &obset);
    assert(n == 0);
    cout << "2号信号以阻塞" << endl;
    (void)n;
    // 重复打印当前的pending信号集
    int count = 0;
    while (1)
    {
        // 获取当前进程的pending信号集
        sigpending(&pending);
        // 显示pending中的没有被递达的信号
        shouPending(pending);
        sleep(2);
        count++;
        if (count == 10)
        {
            int n = sigprocmask(SIG_SETMASK, &obset, nullptr);
            assert(n == 0);
            (void)n;
            cout << "解除2号信号的阻塞" << endl;

        }
    }
    return 0;
}

可是我们并没有看到从1到0,这是因为进程直接终止了,在默认情况下,解除阻塞2号信号直接递达了,需要捕捉一下!

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

static void handler(int signum)
{
    cout<<"捕捉信号:"<<signum<<endl;
}
int main()
{
    //测试捕捉
    signal(2,handler);
    // 定义信号集
    sigset_t bset, obset;
    sigset_t pending;
    // 初始化
    sigemptyset(&bset);
    sigemptyset(&obset);
    sigemptyset(&pending);
    // 添加要进行屏蔽的信号
    sigaddset(&bset, 2);
    // 设置set到内核中
    int n = sigprocmask(SIG_BLOCK, &bset, &obset);
    assert(n == 0);
    cout << "2号信号以阻塞" << endl;
    (void)n;
    // 重复打印当前的pending信号集
    int count = 0;
    while (1)
    {
        // 获取当前进程的pending信号集
        sigpending(&pending);
        // 显示pending中的没有被递达的信号
        shouPending(pending);
        sleep(2);
        count++;
        if (count == 10)
        {
            int n = sigprocmask(SIG_SETMASK, &obset, nullptr);
            assert(n == 0);
            (void)n;
            cout << "解除2号信号的阻塞" << endl;

        }
    }
    return 0;
}

这时我们就看到了当前进程的pending信号集从1变成了0!

还有一个小问题,貌似没有一个接口用来设置我们的pending位图,这是因为我们的所有发送信号的方式,都是修改pending位图的过程

3.问题三

如果我们对所有的信号都阻塞,我们是不是就写了一个不会被一场或者用户杀掉的进程?

static void shouPending(sigset_t &pending)
{
    for (int sig = 1; sig <= 31; sig++)
    {
        if (sigismember(&pending, sig))
        {
            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 sig=1;sig<=31;sig++)
    {
        blockSig(sig);
    }
    sigset_t pending;
    while(1)
    {
        sigpending(&pending);
        shouPending(pending);
        sleep(1);
    }
    return 0;
}

和第一个问题是一样的,9号信号同样也不可以被阻塞!

同样的还有我们的19号暂停命令和20号命令!

所以最终结论,无论是9号信号就不可被捕捉和屏蔽的

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

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

相关文章

flutter给组件设置背景图的操作

可以设置背景图的组件只有一个&#xff0c;那就是Container容器&#xff0c;要想设置背景图&#xff0c;可以使用网路图片&#xff0c;也可以使用本地图片&#xff0c;要是使用本地图片&#xff0c;需要在本地添加一个资源路径&#xff0c;用来管理这些文件&#xff0c;在本地项…

大量文件重命名数字排序有什么好方法?快来看这里

随着数字时代的到来&#xff0c;我们每天都会处理大量的文件&#xff0c;无论是工作还是生活。为了更好地管理和查找这些文件&#xff0c;我们通常会使用数字排序来对它们进行排列。那么&#xff0c;为什么要给大量文件添加数字排序呢&#xff1f; 首先&#xff0c;数字排序可以…

开关电源如何覆铜

开关电源如何覆铜 开关电源覆铜是一个很重要的技术方法&#xff0c;如果没有很好的覆铜&#xff0c;就有可能会造成开关电源芯片的损坏。先介绍常见的开关电源电路&#xff1a; 图 1开关电源电路 从左到右分别是非同步整流Buck电路和同步整流Buck电路&#xff0c;第二排从左到…

开发需求总结10-修改el-form-item的label,实现换行并且修改换行字体的样式

需求描述&#xff1a; 目录 需求描述&#xff1a; 相关代码&#xff1a; 额外拓展&#xff1a; 在form表单上&#xff0c;有个别label可能需要在下方有红色小字用来提示&#xff0c;这条数据的注意点&#xff0c;此时就需要实现label可以换行&#xff0c;并且给下面的小字设置…

C++力扣题目77--组合

给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ] 示例 2&#xff1a; 输入&#xff1a;n 1, k …

2024云渲染,渲染农场带给三维建模行业的影响

在电影和电视的CG特效制作中&#xff0c;三维建模技术是核心组成部分&#xff0c;因为它们能够创造出既细致又引人注目的场景和角色。三维建模和渲染软件等功能的也在日益强大&#xff0c;建模艺术家们可以创作出更加逼真的环境、栩栩如生的人物发丝、动人心弦的光照效果和栩栩…

Nginx设置域名转发到服务器指定的端口

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f525;网站…

Docker 如何安装 MySQL 并实现远程连接

Hello各位小伙伴们大家好&#xff01;我是咕噜铁蛋&#xff01;随着云计算和容器化技术的兴起&#xff0c;Docker 已经成为现代软件开发的核心工具之一。它提供了一种轻量级、可移植、自包含的部署方式&#xff0c;使得开发人员可以更加便捷地构建、测试和发布应用程序。而 MyS…

机器人制作开源方案 | 智能循迹避障小车

作者&#xff1a;刘元青、邹海峰、付志伟、秦怀远、牛文进 单位&#xff1a;哈尔滨信息工程学院 指导老师&#xff1a;姚清元 智能小车是移动式机器人的重要组成部分&#xff0c;而移动机器人不仅能够在经济、国防、教育、文化和生活中起到越来越大的作用&#xff0c;也是研究…

Element UI CascaderPanel级联组件使用和踩坑总结

Element UI CascaderPanel级联组件使用和踩坑总结 问题背景 需求中需要用到Element UI的 CascaderPanel组件&#xff0c;并且支持多选&#xff0c;定制化需求&#xff0c;比如某节点被选择&#xff0c;等价于该节点下面所有子节点都被选择&#xff0c; CascaderPanel组件返回…

K6 性能测试教程:常用功能 - HTTP 请求,指标和检查

这篇文章详细介绍了 K6 中的 HTTP 请求&#xff08;http request&#xff09;功能&#xff0c;解析了常用的性能指标和检查功能。通过 HTTP 请求模拟用户行为&#xff0c;了解性能指标以评估系统响应。文章还深入讲解了如何配置和执行检查&#xff0c;确保性能符合预期标准。无…

什么是技术架构?架构和框架之间的区别是什么?怎样去做好架构设计?(一)

什么是技术架构?架构和框架之间的区别是什么?怎样去做好架构设计?(一)。 在软件行业,对于什么是架构,都有很多的争论,每个人都有自己的理解。在不同的书籍上, 不同的作者, 对于架构的定义也不统一, 角度不同, 定义不同。 一、架构是什么 Linux 有架构,MySQL 有架构,J…

基于dinoV2分类模型修改

前言 dinoV2已经发布有一段时间了&#xff0c;faecbook豪言直接说前面的结构我们都不需要进行修改&#xff0c;只需要修改最后的全连接层就可以达到一个很好的效果。我们激动的揣摸了下自己激动的小手已经迫不及待了&#xff0c;这里我使用dinoV2进行了实验&#xff0c;来分享…

7.3 数据库的基本查询

数据库的基本查询 1. 提要2. 简单查询3. 高级查询3.1 数据分页_limit3.2 排序_order by3.3 查询去重_distinct 4. 条件查询 1. 提要 2. 简单查询 3. 高级查询 3.1 数据分页_limit 3.2 排序_order by 3.3 查询去重_distinct 4. 条件查询

“与辉同行”首秀金额过亿,一个东方甄选拆出无数个董宇辉?

董宇辉又爆了&#xff01; 小作文风波后&#xff0c;董宇辉不仅摇身一变成东方甄选新股东&#xff0c;还自立门户成立了新直播间“与辉同行”。 首秀当天在抖音平台正式开播&#xff0c;首秀就创下了惊人的成绩&#xff1a;直播间人气高达1.2亿&#xff0c;销售额超过1.1亿&a…

MongoDB Compass 的教程

第一步&#xff1a;建立连接 点击Save&Connect 增加数据库&#xff1a; 填写数据库名字和文档名字并点击Create Database 删除文档&#xff1a; 创建文档&#xff1a; 插入文档数据 {Id:1001,name:"cyl",age:21} 插入成功&#xff1a; 更改原有数据 删除原有数据…

【LeetCode】202. 快乐数(简单)——代码随想录算法训练营Day06

题目链接&#xff1a;202. 快乐数 题目描述 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终…

Multimodal Contrastive Training for Visual Representation Learning

parameterize the image encoder as f i q _{iq} iq​ query feature q i i _{ii} ii​&#xff0c;key feature k i i _{ii} ii​ parameterize the textual encoder as f c q ( ⋅ ; Θ q , Φ c q ) f_{cq}(; Θ_q, Φ_{cq}) fcq​(⋅;Θq​,Φcq​)&#xff0c;momentum …

西贝柳斯音乐记谱软件Avid Sibelius Ultimate 2023中文激活版

Avid Sibelius(西贝柳斯终极解锁版) 是一款记谱软件&#xff0c;从有抱负的作曲家和词曲作者到教师和学生&#xff0c;任何人都可以快速轻松地开始创作和分享音乐。对于那些还不熟悉使用符号软件的人来说&#xff0c;直观的界面将引导您完成整个过程。磁性布局可防止对象相互碰…

API可视化编排如何实现

企业随着前后端分离架构、微服务架构、中台战略、产业互联互通的实施必将产生大量的各种协议的API服务&#xff0c;API将成为企业的数字化资产且API会越来越多&#xff0c; API服务之间的相互调用和依赖情况也随之越来越多和复杂。业务系统与业务系统之间、关联企业之间的API都…