Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Linux】详解信号的保存&&信号屏蔽字的设置

【Linux】详解信号的保存&&信号屏蔽字的设置

作者头像
用户10923276
发布于 2024-05-03 00:41:07
发布于 2024-05-03 00:41:07
25700
代码可运行
举报
运行总次数:0
代码可运行

一、信号处理的一些常见概念

  • 实际执行信号的处理动作称为信号递达(Delivery)。
  • 信号从产生到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。
  • 注意:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
  • 阻塞一个信号和是否收到这个信号是没有关系的。也就是说,在还没收到一个信号之前就可以在内核中设置对这个信号进行阻塞。

二、信号保存以及阻塞的内核级理解

在进程的PCB中,其实是有三张表。

一张为block位图(阻塞位图),也就是一个32位的整形变量,其中取高31位来表示是否阻塞对应的信号,比如说block位图中第0个比特位不用,第1个比特位表示是否阻塞1号信号,第一个比特位为1就表示阻塞1号信号,为0就表示不阻塞1号信号,依次类推,第2到第31个比特位也是同样的道理。

一张为pending位图(未决位图),也是一个32位的整形变量,其中取高31位来表示是否收到对应的信号,比如说pending位图中第0个比特位不用,第1个比特位表示是否收到1号信号,第一个比特位为1就表示收到1号信号,为0就表示没有收到1号信号。

另一张是一个函数指针数组,该数组中每一个下标中都存放了收到对应信号后的处理方法。如果我们不对方法做自定义写入,那么进程在收到对应信号后执行的就是默认的方法,如果自定义写入了那执行的就是我们写入的方法。

在上图中,三个数组(前两张位图也可以看成数组)应该横着看,依次表示该信号是否被阻塞,是否收到该信号,以及执行该信号的处理方法。 常规信号在递达之前产生多次只计一次,也就是说,当在一段时间内有多个相同的信号到来但却来不及被处理时,在pending位图里只会记录一次而实时信号在递达之前产生多次可以依次放在一个队列里。

三、查看pending位图

其中sigset_t类型的解释就在下面,set为一个输出型参数,我们传入一个sigset_t类型的参数set,pending位图中的值就被set参数获得了。如果获取成功sigpending函数返回0,是被返回-1。

四、设置信号屏蔽字操作(修改block位图)

从上面的介绍中我们也可以看到,其实block位图和pending位图的结构是十分相似的,所以未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,可以用来修改进程block位图中的信号屏蔽字sigset_t就是一种数据类型,跟int、double这些数据类型没有区别。

3.1、信号集操作函数

sigset_t虽然是一种数据类型,但是我们并不能直接手动的修改sigset_t类型的值,必须要调用对应的系统调用函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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置1位,表示该信号集的有效信号包括系统支持的所有信号。
  • sigaddset:在set信号集中添加signo信号。
  • sigdelset:在set信号集中删除signo信号。
  • sigismember:用于测试一个指定的信号是否已加入至一个特定的信号集中。

我们设置完信号集set的值后,set并没有被设置进进程的PCB中,还需要我们调用系统调用函数设置。

3.2、设置信号屏蔽字

利用sigprocmask系统调用函数可以设置进程的信号屏蔽字

第一个参数how有三个选项:

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

第二个参数set是我们设置的信号屏蔽字,第三个参数为输出型信号屏蔽字,是原来的信号屏蔽字。

3.3、设置信号屏蔽字的例子

下面是一个设置屏蔽2号信号,有解除屏蔽2号信号的例子。在程序运行起来到程序运行到20秒期间,我给程序发送2号信号,应该看到pending位图中2号信号的位置为1但程序不退出,到了20秒时程序退出。

下面是打印pending表的函数,如果收到信号,对应的比特位就置1,如果没有收到就置0。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void print(const sigset_t& pending)
{
    for(int i = 31; i>=1; i--)
    {
        if(sigismember(&pending, i))
            std::cout << "1";
        else
            std::cout << "0";
    }
    std::cout << std::endl;
}

2号信号加入到信号屏蔽集中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    sigset_t set, oldset;
    sigemptyset(&set);
    sigemptyset(&oldset);

    sigaddset(&set, 2);//将2号信号加入到要屏蔽的信号集中

set设置进进程的PCB中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //设置set进block位图中
    int n = sigprocmask(SIG_SETMASK, &set, &oldset);
    if(n == -1)
    {
        std::cout << "设置屏蔽字错误!" << std::endl;
        return 1;
    }

查看pending表,观察退出状态:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    int cnt = 0;

    //查看pending位图,给进程发送2号信号,pending位图中应该出现2号信号,但是进程不会退出
    //等到20秒时程序退出
    while(true)
    {
        cnt++;
        if(cnt == 20)
            sigprocmask(SIG_UNBLOCK, &set, &oldset);
        sigset_t pending;
        sigemptyset(&pending);
        int m = sigpending(&pending);
        print(pending);
        sleep(1);
    }

发送2号信号,程序到20秒时退出:

四、总结

31个信号中并不是所有信号都可以被屏蔽掉,9号信号(SIGKILL)和19号信号(SIGSTOP)是无法被屏蔽掉的。若想获取上述的完整的代码,请移步本人码云:240427 · 沈旭彬/C++代码 - 码云 - 开源中国 (gitee.com)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
初识Linux · 信号保存
前文我们已经介绍了信号产生,在时间的学习线上,信号的学习分为预备知识,信号产生,信号保存,信号处理,本文我们学习信号保存,在前言部分,我们介绍几个信号保存中的概念。
_lazy
2024/11/19
2240
初识Linux · 信号保存
【Linux】信号的保存
我们也介绍了core term两种默认操作,core在执行信号后会形成一份core文件(默认是关闭的,因为原本core文件的后缀是pid,运行出错后会创建core文件,导致磁盘空间不足),该文件里存储了出错原因,可以再gdb调试时进行使用。
叫我龙翔
2024/06/23
2900
【Linux】信号的保存
Linux进程信号【信号保存】
信号从产生到执行,并不会被立即处理,这就意味着需要一种 “方式” 记录信号是否产生,对于 31 个普通信号来说,一个 int 整型就足以表示所有普通信号的产生信息了;信号还有可能被 “阻塞”,对于这种多状态、多结果的事物,操作系统会将其进行描述、组织、管理,这一过程称为 信号保存 阶段
北 海
2023/07/01
5390
Linux进程信号【信号保存】
Linux信号的保存和处理
每一个信号都有着三张表:block、pending、handler。 两张位图+一张函数指针数组=进程识别信号
南桥
2024/07/26
1750
Linux信号的保存和处理
【Linux进程信号】Linux信号机制深度解析:保存与处理技巧
🔍前言:在Linux操作系统的广阔天地中,信号机制无疑是一个充满挑战与机遇的领域。信号,作为进程间通信的一种重要方式,不仅承载着丰富的信息,还扮演着进程控制与管理的重要角色。然而,对于许多初学者而言,信号的保存与处理往往是一个难以逾越的障碍
Eternity._
2024/10/15
2210
【Linux进程信号】Linux信号机制深度解析:保存与处理技巧
【Linux】进程信号的发送和保存
通过指令man -7 signal查看信号的手册,然后往下翻翻可以看到普通信号发出后对应的操作,以及它们的信号编号,和详细描述信息
s-little-monster
2025/04/01
860
【Linux】进程信号的发送和保存
信号初相识:Linux 内核的 “隐形使者”
在 Linux 系统的广袤世界里,信号(Signal)宛如一位神秘的隐形使者,默默地在后台发挥着至关重要的作用。它是一种异步通信机制,如同古代的烽火台,当特定事件发生时,便会燃起 “烽火”,通知进程做出相应的反应。信号可以来自硬件异常,如内存访问错误、除零错误;也能由软件条件触发,像是用户按下特定的按键组合,或者程序主动调用系统函数发送信号 。
用户11396661
2025/02/28
960
【linux学习指南】详解Linux进程信号保存
如果在进程解除对某信号的阻塞之前这种信号产⽣过多次,将如何处理?POSIX.1允许系统递送该信 号⼀次或多次。Linux是这样实现的:常规信号在递达之前产⽣多次只计⼀次,⽽实时信号在递达之 前产⽣多次可以依次放在⼀个队列⾥。本章不讨论实时信号。
学习起来吧
2024/12/01
1450
【linux学习指南】详解Linux进程信号保存
【Linux】信号保存与信号捕捉处理
那么在学习信号保存之前,我们先了解一下信号的发送,我们知道普通信号一共有31个,如下:
YoungMLet
2024/03/01
2580
【Linux】信号保存与信号捕捉处理
【linux】信号的保存和递达处理
        上节我们了解到了预备(信号是什么,信号的基础知识)再到信号的产生(四种方式)。今天我们了解信号的保存。信号产生,进程不一定立马就去处理,而是等合适的时间去处理,那么在这段时间内,进程就需要保存信号,到了合适时间再去执行!
The sky
2023/10/17
2200
【linux】信号的保存和递达处理
一文搞懂Linux信号【下】
在观看本博客之前,建议大家先看一文搞懂Linux信号【上】。由于上一篇博客篇幅太长,为了更好的阅读体验,我拆成了两篇博客。那么接下来,在上一篇的基础上,我们继续学习Linux信号部分。本篇我们主要谈论信号保存和信号处理。
破晓的历程
2024/06/24
1530
一文搞懂Linux信号【下】
Linux信号
在生活中也有诸多信号,这些信号通常不是由我们发起的,而是我们接收以后对对应的信号做处理;最常见的莫过于红绿灯了,当红绿灯发出信号时(红灯,绿灯,黄灯);我们会有对应的行为,比如绿灯我们知道当前可以行走,红灯的时候我们需要等一等。对信号产生以后我们知道该做什么,这是因为我们曾经接受了对于这些信号的教育,知道当这些信号产生以后我们需要做什么。
始终学不会
2023/10/17
4410
Linux信号
【Linux】进程信号——信号保存和信号捕捉
信号递达:指 操作系统 将一个信号(Signal)从内核传递到目标进程 的过程。它是 信号处理机制 中的关键步骤。 信号未决:信号从产生到递达之间的状态 信号阻塞 进程或线程可以暂时屏蔽某些信号,使它们在阻塞期间不会递达和处理。一旦解除阻塞,信号会被递达并处理。
用户11305458
2025/03/05
3820
【Linux】进程信号——信号保存和信号捕捉
Linux进程信号总结
不难看出上面的死循环在代码层面是永远无法结束程序的,那是否还有别的办法?对于死循环来说,最好的方式就是使用Ctrl+C对其进行终止。
咬咬
2024/07/20
1290
Linux进程信号总结
linux系统编程之信号(三):信号的阻塞与未决
一、信号在内核中的表示 实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号,SIGKILL 和
s1mba
2017/12/28
2.3K0
linux系统编程之信号(三):信号的阻塞与未决
【Linux】进程信号(中)
为什么除0就报错了呢? 当代码除0时,程序运行后就崩溃了,程序运行变为进程,进程运行代码时出现了非法代码,进程退出了
lovevivi
2023/10/16
3370
【Linux】进程信号(中)
Linux系统-进程信号
注:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作
用户9645905
2022/11/15
3.6K0
Linux系统-进程信号
【进程信号】五、信号集操作接口详解
​ 还记得我们上面讲过的 sigset_t 类型吗,sigset_t 类型对于每种信号用一个 bit 表示 “有效” 或 “无效” 状态,至于这个类型内部如何存储这些 bit 则依赖于系统实现,从使用者的角度是不必关心的,因为不同的操作系统可能对 sigset_t 变量的定义不一样,有的可能是变量,有的可能是数组,有的可能是封装在结构体内等等。
利刃大大
2025/04/20
860
【进程信号】五、信号集操作接口详解
Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
首先区分一下Linux信号跟进程间通信中的信号量,它们的关系就犹如老婆跟老婆饼一样,没有一毛钱的关系。
二肥是只大懒蓝猫
2023/03/30
1.4K0
Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
进程信号
kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。raise函数可以给当前进程发送指定的信号(自己给自己发信号)。
ljw695
2024/11/21
1210
进程信号
相关推荐
初识Linux · 信号保存
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验