Linux-信号2

文章目录

  • 前言
  • 一、信号是如何保存的?
    • 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);
    • int sigpending(sigset_t *set);
    • int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
      • 1.SIG_BLOCK
      • 2.SIG_UNBLOCK
      • 3.SIG_SETMASK
  • 二、学习步骤
    • 我们提出三个问题并对问题进行一一解答来进行我们的学习
      • 问题1. 如果我们将一个死循环进程的所有信号都捕捉,是不是该进程无法被退出?
      • 问题2. 如果我们将一个信号block阻塞,并发送对应信号,pending表的对应该信号bit位是不是由0置1?
      • 问题3. 如果我们将一个死循环进程的所有信号都阻塞,是不是该进程也无法被退出?
    • 1.解答问题1
    • 2.解答问题2
    • 3.解答问题3


前言

上节课我们学习了信号产生到处理过程的现象以及信号的捕捉,这节课主要学习信号的保存。
我们需要熟练使用以下函数

#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);
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
int sigpending(sigset_t *set);


一、信号是如何保存的?

上节课我们说过,信号是在进程的PCB中存储 信号的位图,而实际上,可不止有一个表(位图)。
在这里插入图片描述

block信号集是用以保存被block阻塞的信号,一般被称为信号屏蔽字(阻塞信号集),pending信号集就是我们上节课所说的那个收到信号即相对位由0置1的位图,一般被称为未决信号集

对于阻塞,这是提前预设好的,目的是为了让该进程屏蔽该信号,所以如果一个信号被阻塞,而又收到了该信号,虽然pending信号集由0置1,但是不进行delivery(信号递达:信号递达操作即信号的处理)操作。

而这两个信号集,在我们看来理解其实就是位图,但是OS将他们封装成了自定义类型sigset_t,通过这样的封装,对于我们用户就无法随心所欲地更改其信号集的数据,只能通过OS提供给我的系统接口函数。
现在来认识一下系统交给我们的一些接口函数。

int sigemptyset(sigset_t *set);

函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有
效信号。
成功返回0,出错返回-1

int sigfillset(sigset_t *set);

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

int sigaddset (sigset_t *set, int signo);

函数sigaddset用于将set所指向的信号集的signo信号置位。
成功返回0,出错返回-1

int sigdelset(sigset_t *set, int signo);

函数sigdelset用于将set所指向的信号集的signo信号置零。
成功返回0,出错返回-1

int sigismember(const sigset_t *set, int signo);

函数sigismember用于判断set所指向信号集的signo信号是否为1。
是则返回1,否则为0。

int sigpending(sigset_t *set);

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

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

函数sigprocmask用于更改block信号集,参数how为选项,该函数提供三种选项

1.SIG_BLOCK

该选项是希望在目前的信号屏蔽字添加set信号集的有效信号,相当于mask=mask|set

2.SIG_UNBLOCK

该选项是希望在目前的信号屏蔽字去除set信号集的有效信号,相当于mask=mask&(~set)

3.SIG_SETMASK

该选项就比较暴力些,相当于mask=set

而参数oset为输出型参数,用于保存老信号集。

需要注意的,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的
状态。

二、学习步骤

我们提出三个问题并对问题进行一一解答来进行我们的学习

问题1. 如果我们将一个死循环进程的所有信号都捕捉,是不是该进程无法被退出?

问题2. 如果我们将一个信号block阻塞,并发送对应信号,pending表的对应该信号bit位是不是由0置1?

问题3. 如果我们将一个死循环进程的所有信号都阻塞,是不是该进程也无法被退出?

1.解答问题1

代码如下(示例):

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

void catchSig(int signum)
{
    std::cout << "pid " << getpid() <<" :捕捉到信号 " << signum << std::endl; 
}

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

    while(1)
    {
        std::cout << "pid " << getpid() << " :进程运行中... " <<std::endl;
        sleep(1);
    }
    return 0;
}

这个程序会在运行时捕捉1-31号的所有信号,那么是不是这个进程就无法退出了呢?
我们通过命令行依次输入kill命令来进行对该进程发送信号,发现在发送9号信号的时候,进程还是被终止了,说明进程的9号信号没有被捕捉!
在这里插入图片描述
所以这里的结论就是如果我们将一个死循环进程的所有信号都捕捉,该进程仍然可以通过9号信号退出,因为设计OS的人知道,如果有恶意程序真的将所有信号都可以捕捉,那么后果是十分严重的!

2.解答问题2

代码如下(示例):

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

void ShowSet(sigset_t &set)
{
    for (int i = 1; i <= 31; i++)
    {
        // 通过sigismember来打印我们的pending信号集
        std::cout << sigismember(&set, i);
    }
    std::cout << std::endl;
}

int main()
{
    sigset_t set;
    sigset_t block;
    sigset_t oset;
    // 1.进行初始化
    sigemptyset(&set);
    sigemptyset(&block);
    sigemptyset(&oset);

    // 2.阻塞2号信号
    sigaddset(&block, 2);
    sigprocmask(SIG_BLOCK, &block, &oset);

    std::cout << "pid " << getpid() << std::endl;
    // 3.循环打印未决信号集
    while (1)
    {
        // 3.1 获取当前的未决信号集
        sigpending(&set);
        ShowSet(set);
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
我们很清楚的看到第二位由0置1了。
所以结论就是如果我们将一个信号block阻塞,并发送对应信号,pending表的对应该信号bit位是由0置1。

3.解答问题3

代码如下(示例):

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

void ShowSet(sigset_t &set)
{
    for (int i = 1; i <= 31; i++)
    {
        // 通过sigismember来打印我们的pending信号集
        std::cout << sigismember(&set, i);
    }
    std::cout << std::endl;
}

void SendSig(int signum)
{
    if ((signum != 19) &&(signum != 9) && (signum <= 31))
        raise(signum);
}

int main()
{
    sigset_t set;
    sigset_t block;
    sigset_t oset;
    // 1.进行初始化
    sigemptyset(&set);
    sigemptyset(&block);
    sigemptyset(&oset);

    // 2.阻塞所有信号
    for (int i = 1; i <= 31; i++)
    {
        sigaddset(&block, i);
    }
    sigprocmask(SIG_SETMASK, &block, &oset);

    // 3.循环打印未决信号集
    int count = 1;
    while (1)
    {
        // 3.1 获取当前的未决信号集
        sigpending(&set);
        ShowSet(set);
        SendSig(count++);
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
我们看到这样的情况,可以得出看出9号信号和19号信号是不可屏蔽的!

所以这里的结论就是如果我们将一个死循环进程的所有信号都屏蔽,该进程仍然可以通过9号信号退出。


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

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

相关文章

leetcode 长度最小的子数组

在本题中&#xff0c;我们可以知道&#xff0c;是要求数组中组成和为target的最小子数组的长度。所以&#xff0c;我们肯定可以想到用两层for循环进行遍历&#xff0c;然后枚举所有的结果进行挑选&#xff0c;但这样时间复杂度过高。 我们可以采用滑动窗口&#xff0c;其实就是…

NoSQL--1.虚拟机网络配置

目录 1.初识NoSQL 1.1 NoSQL之虚拟机网络配置 1.1.1 首先&#xff0c;导入预先配置好的NoSQL版本到VMware Workstation中 1.1.2 开启虚拟机操作&#xff1a; 1.1.2.1 点击开启虚拟机&#xff1a; 1.1.2.2 默认选择回车CentOS Linux&#xff08;3.10.0-1127.e17.x86_64) 7 …

同样是证书,NPDP和PMP有什么区别?

PMP和NPDP的区别是啥&#xff1f; PMP、NPDP证书考哪个更有用&#xff1f;还是两个都考&#xff1f; PMP和NPDP哪个更适合现在及以后发展&#xff1f; PMP和NPDP这两哪个含金量更高&#xff1f; 一&#xff0c;关于PMP和NPDP PMP和NPDP都是美国PMI/PDMA的专业考试&#xf…

C语言中的分支和循环语句:从入门到精通

分支和循环语句 1. 前言2. 预备知识2.1 getchar函数2.2 putchar函数2.3 计算数组的元素个数2.4 清屏2.5 程序的暂停2.6 字符串的比较 3. 结构化3.1 顺序结构3.2 分支结构3.3 循环结构 4. 真假性5. 分支语句&#xff08;选择结构&#xff09;5.1 if语句5.1.1 语法形式5.1.2 else…

Stable Cascade又升级了,现在只需要两个模型

Stable Cascade这个模型&#xff0c;大家如果还有印象的话&#xff0c;是需要下载三个模型的&#xff0c;分别是Stage_a,Stage_b和Stage_c,如果全都下载下来&#xff0c;需要20多个G&#xff0c;但是最近使用ComfyUI做尝试的时候&#xff0c;发现官方的案例中已经没有用到单独的…

数据审计 -本福德定律 Benford‘s law (sample database classicmodels _No.6)

数据审计 -本福德定律 Benford’s law 准备工作&#xff0c;可以去下载 classicmodels 数据库资源如下 [ 点击&#xff1a;classicmodels] 也可以去我的博客资源下载 文章目录 数据审计 -本福德定律 Benfords law 前言一、什么是 本福德定律&#xff1f;二、数学公式三、应用…

单细胞Seurat - 降维与细胞标记(4)

本系列持续更新Seurat单细胞分析教程&#xff0c;欢迎关注&#xff01; 非线形降维 Seurat 提供了几种非线性降维技术&#xff0c;例如 tSNE 和 UMAP&#xff0c;来可视化和探索这些数据集。这些算法的目标是学习数据集中的底层结构&#xff0c;以便将相似的细胞放在低维空间中…

Grpc项目集成到java方式调用实践

背景&#xff1a;由于项目要对接到grcp 的框架&#xff0c;然后需要对接老外的东西&#xff0c;还有签名和证书刚开始没有接触其实有点懵逼。 gRPC 是由 Google 开发的高性能、开源的远程过程调用&#xff08;RPC&#xff09;框架。它建立在 HTTP/2 协议之上&#xff0c;使用 …

从零开始手写RPC框架(3)——ZooKeeper入门

目录 ZooKeeper简介ZooKeeper中的一些概念 ZooKeeper安装与常用命令常用命令 ZooKeeper Java客户端 Curator入门 ZooKeeper简介 是什么&#xff1f; ZooKeeper 是一个开源的分布式协调服务&#xff0c;本身就是一个分布式程序&#xff08;只要半数以上节点存活&#xff0c;Zo…

django-admin登录窗口添加验证码功能-(替换原有的login.html)captcha插件

需求&#xff1a; 1&#xff1a;更改django框架的admin登录窗口标题 2&#xff1a;在admin登录窗口中添加验证码功能 3&#xff1a;验证码允许点击更换 步骤如下&#xff1a; 1:安装插件以及在安装列表中添加插件 2:自定义表单forms.py 3:创建login.html文件(复制django内置的l…

中国电子学会2020年6月份青少年软件编程Sc ratch图形化等级考试试卷四级真题。

第 1 题 【 单选题 】 1.执行下面程序&#xff0c;输入4和7后&#xff0c;角色说出的内容是&#xff1f; A&#xff1a;4&#xff0c;7 B&#xff1a;7&#xff0c;7 C&#xff1a;7&#xff0c;4 D&#xff1a;4&#xff0c;4 2.执行下面程序&#xff0c;输出是&#xff…

备战蓝桥杯Day22 - 计数排序

计数排序问题描述 对列表进行排序&#xff0c;已知列表中的数范围都在0-100之间。设计时间复杂度为O(n)的算法。 比如列表中有一串数字&#xff0c;2 5 3 1 6 3 2 1 &#xff0c;需要将他们按照从小到大的次序排列&#xff0c;得到1 1 2 2 3 3 5 6 的结果。那么此时计数排序是…

每天一道leetcode:14.最长公共前缀(简单)

⭐今日份题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例1 输入&#xff1a;strs ["flower","flow","flight"] 输出&#xff1a;"fl" 示例2 输入&#…

制作镜像与配置推送阿里云仓库

一、制作jdk镜像 1.1、Alpine linux简介 Alpine Linux是一个轻量级的Linux发行版&#xff0c;专注于安全、简洁和高效。它采用了musl libc和BusyBox&#xff0c;使得系统资源占用较少&#xff0c;启动速度较快。 Alpine Linux也提供了一个简单的包管理工具APK&#xff0c;(注…

MySQL:索引的优化方法

索引是帮助存储引擎快速获取数据的一种数据结构&#xff0c;形象的说就是索引是数据的目录。 索引创建的时机&#xff1a; 索引并不是越多越好的&#xff0c;虽然他再查询时会提高效率&#xff0c;但是保存索引和维护索引也需要一定的空间和时间成本的。 不创建索引&#xff1a…

消防主机报故障时发出故障及原因及解决办法!

本文以青鸟消防JBF-11SF为例。 其他型号或品牌的消防主机也可参考。 开机前&#xff0c;必须先测量系统接线的绝缘电阻&#xff0c;确保各绝缘电阻满足以下要求&#xff1a; 1&#xff09;空载时各电路信号线之间的绝缘值应大于5K欧姆。 2&#xff09;正常天气条件下&#x…

10 计算机结构

冯诺依曼体系结构 冯诺依曼体系结构&#xff0c;也被称为普林斯顿结构&#xff0c;是一种计算机架构&#xff0c;其核心特点包括将程序指令存储和数据存储合并在一起的存储器结构&#xff0c;程序指令和数据的宽度相同&#xff0c;通常都是16位或32位 我们常见的计算机,笔记本…

C语言第三十四弹---动态内存管理(下)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 动态内存管理 1、动态内存经典笔试题分析 1.1、题目1 1.2、题目2 1.3、题目3 1.4、题目4 2、柔性数组 2.1、柔性数组的特点 2.2、柔性数组的使用 2.3、…

68-解构赋值,迭代器,生成器函数,Symbol

1.解构赋值(针对数组array&#xff0c;字符串String及对象object以) 结构赋值是一种特殊的语法&#xff0c;通过将各种结构中的元素复制到变量中达到"解构"的目的&#xff0c;但是数组本身没有改变 1.1解构单层数组 <script>let arr [1,2,3,4,5];//获取数组…