【Linux取经路】信号的发送与保存

2024-06-06 22:04

本文主要是介绍【Linux取经路】信号的发送与保存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

文章目录

  • 一、重新理解发送信号
  • 二、信号的保存、阻塞信号的概念
  • 三、信号集操作函数
    • 3.1 sigprocmask
    • 3.2 sigpending
  • 四、阻塞信号代码验证
  • 五、结语

一、重新理解发送信号

进程通过位图来实现对普通信号(1-31号信号)的保存,该位图保存在进程的 task_struct 结构体中。比特位的内容是 0 还是 1,表明是否收到信号;比特位的位置是第几个,表明信号的编号。**发送信号的本质就是,操作系统去修改 task_struct 的信号位图中对应的比特位。**因为操作系统是进程的管理者,所以只能由操作修通去执行修改动作。由于对普通信号采用的是位图结构,所以对于某一个特定的信号,只能保存一次,即进程先收到了一个 2 号信号,还没有对 2 信号处理,此时又收到一个 2 号信号,因为位图只能确定进程是否少到了某一个信号,无法确定收到某个信号的个数,所以,最终 2 号信号只能被执行一次。对实时信号采用的是队列进行管理,实时信号需要立即处理,并且操作系统发了多少个实时信号,对应的进程就要处理多少次。

**操作系统本来可以直接杀掉或者暂停一个进程,那为什么还要搞出信号这一套东西呢?**答案是,操作系统还要考虑上层用户,在异常产生的时候,如果操作系统直接就把程序终止了,那历史上可能产生了很多重要的数据没有保存,导致数据丢失,操作系统为了避免承担责任,所以有了信号这一概念。在进程出现异常的时候,操作系统先给进程发送信号,相当于是给它提个醒,你已经出异常了,快干收尾工作吧,这也是信号捕捉方法里需要完成的工作。

二、信号的保存、阻塞信号的概念

信号相关概念

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

image-20240309085224850

SIG_DEFL:执行信号的默认处理动作;SIG_IGN:对信号执行忽略动作。

image-20240309090948325

三、信号集操作函数

sigset_t 称为信号集,是操作系统给用户提供的一种数据类型,用来描述和 blockpending 一样的位图,于此同时,操作系统还给我们提供了很多信号集操作函数,我们可以通过这些函数去修改信号集。

#include <signal.h>
int sigemptyset(sigset_t *set); // 将位图全部设置为 0
int sigfillset(sigset_t *set); // 将位图全部都设置为 1
int sigaddset (sigset_t *set, int signo); // 将位图中的某一位设置为 1
int sigdelset(sigset_t *set, int signo); // 将位图中的某一位设置为 0
int sigismember(const sigset_t *set, int signo); // 判断一个信号是否在信号集中,不在返回0,在返回1,出错返回-1

3.1 sigprocmask

该函数是专门针对系统中的 block 位图的。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 
// 返回值:若成功则为0,若出错则为-1

如果 oset 是非空指针,则读取进程的当前信号屏蔽字通过 oset 参数传出。如果 set 是非空指针,则更改进程的信号屏蔽字,参数 how 指示如何更改。如果 osetset 都是非空指针,则先将原来的信号屏蔽字备份到 oset 里,然后根据 sethow 参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

选项含义
SIG_BLOCKset 包含了我们希望添加到当前信号屏蔽子中的信号,相当于 `mask = mask
SIG_UNBLOCKset 包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于 mask = mask& (~set)
SIG_SETMASK设置当前信号屏蔽子为 set 所指向的值,相当于 mask = set

3.2 sigpending

该函数是专门针对系统中的 pending 位图的。

#include <signal.h>
int sigpending(sigset_t *set);

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

四、阻塞信号代码验证

#include <iostream>
#include <signal.h>
#include <unistd.h>using namespace std;void PrintPending(const sigset_t &pset)
{for(int i = 31; i >= 1; i--){cout << sigismember(&pset, i);}cout << endl;
}void handler(int signum)
{cout << "catch a signum: " << signum << endl;
}int main()
{signal(2, handler);// 1. 先对 2 号信号进行屏蔽// 数据预备工作sigset_t bset, oset; sigemptyset(&bset); // 先将信号集清空sigemptyset(&oset); // 先将信号集清空sigaddset(&bset, 2); // 给 bset 中添加上 2 号信号// 调用系统调用,将数据设置进内核sigprocmask(SIG_SETMASK, &bset, &oset);// 2. 重复打印当前进程的 pending 信号集// 在重复打印期间向进程发送 2 号信号,因为 2 号信号被屏蔽了,所以 2 号信号会一直被保存在 pending 中sigset_t pset; // pendingsigemptyset(&pset);int cnt = 0;while(true){int n = sigpending(&pset);if(n < 0) continue;PrintPending(pset);sleep(1);cnt++;if(cnt == 15){cout << "unblock 2 signo" << endl;// 解除阻塞sigdelset(&bset, 2);sigprocmask(SIG_SETMASK, &oset, nullptr);}}return 0;
}

image-20240309102707014

9 号和 19 号信号不能被屏蔽,也不能被捕捉。

五、结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,春人的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是春人前进的动力!

在这里插入图片描述

这篇关于【Linux取经路】信号的发送与保存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1037350

相关文章

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Linux卸载自带jdk并安装新jdk版本的图文教程

《Linux卸载自带jdk并安装新jdk版本的图文教程》在Linux系统中,有时需要卸载预装的OpenJDK并安装特定版本的JDK,例如JDK1.8,所以本文给大家详细介绍了Linux卸载自带jdk并... 目录Ⅰ、卸载自带jdkⅡ、安装新版jdkⅠ、卸载自带jdk1、输入命令查看旧jdkrpm -qa

Linux samba共享慢的原因及解决方案

《Linuxsamba共享慢的原因及解决方案》:本文主要介绍Linuxsamba共享慢的原因及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux samba共享慢原因及解决问题表现原因解决办法总结Linandroidux samba共享慢原因及解决

新特性抢先看! Ubuntu 25.04 Beta 发布:Linux 6.14 内核

《新特性抢先看!Ubuntu25.04Beta发布:Linux6.14内核》Canonical公司近日发布了Ubuntu25.04Beta版,这一版本被赋予了一个活泼的代号——“Plu... Canonical 昨日(3 月 27 日)放出了 Beta 版 Ubuntu 25.04 系统镜像,代号“Pluc

Linux安装MySQL的教程

《Linux安装MySQL的教程》:本文主要介绍Linux安装MySQL的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux安装mysql1.Mysql官网2.我的存放路径3.解压mysql文件到当前目录4.重命名一下5.创建mysql用户组和用户并修

Linux上设置Ollama服务配置(常用环境变量)

《Linux上设置Ollama服务配置(常用环境变量)》本文主要介绍了Linux上设置Ollama服务配置(常用环境变量),Ollama提供了多种环境变量供配置,如调试模式、模型目录等,下面就来介绍一... 目录在 linux 上设置环境变量配置 OllamPOgxSRJfa手动安装安装特定版本查看日志在

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用