当前位置: 首页 > news >正文

深入了解linux系统—— 进程信号的产生

前言

进程在收到信号之后,可以立即处理,也可以在合适的时间再处理(1-31号普通信号可以不被立即处理)

信号不是被立即处理,信号就要被保存下来,让进程在合适的时间再去处理。

相关概念

在了解进程是如何保存信号之前,先了解一下一些概念:

  • 信号递达:进程实际执行信号的处理动作
  • 信号未决:信号从产生到递达的状态
  • 阻塞:进程可以阻塞某一个信号;(被阻塞的信号不会被递达,直到解除对信号的阻塞,该信号才会被递达)
  • 忽略:是进程对于已递达的信号的一种处理方式。

信号保存

进程要将信号保存下来,在合适的时候处理;保存信号不仅要保存是否存在信号,也要保存进程是否阻塞信号以及进程对于信号的处理方式。

Linux内核中,对于信号存在三张表分别是:blockpendinghandler;它们分别存储了进程对于信号的阻塞信号,收到信号以及进程对于信号的处理方式。

每一个信号都有阻塞、未决两个标识位以及处理动作,这分别和blockpendinghandler表一一对应。

  1. block表,表示进程对于信号的阻塞情况;
  2. pending表,表示处于未决的信号情况;
  3. handler表,函数指针表,存储着进程对于信号的处理方式。

对于blockpending,可以简单理解为位图,对于1-31号信号,每一个信号对应一个bit位;

blockbit位为1表示进程阻塞该信号,pendingbit位为1表示该信号处于未决状态(进程收到该信号)。

对于handler表,其存储的是进程对于信号的处理方式。

在这里插入图片描述

了解了信号的保存方式blockpendinghandler表;

那发送信号的本质就是将进程的task_struct中的pending表对应的bit位置1(修改内核数据结构对象)

进程处理信号本质就是检查进程task_structblock表是否阻塞信号、pending表是否存在信号,然后进行调用handler表中进程对于信号的处理方法。

信号集sigset_t

信号保存的blockpending表,都是以位图的方式来保存信号阻塞和未决的状态;01

对于阻塞和未决标识都可以使用sigset_t(信号集)这一数据类型来存储。

信号集sigset_t,可以表示信号有效无效的状态。

在阻塞信号集中,有效无效表示信号是否被阻塞。

在未决信号集中,有效无效表示信号是否处于未决状态。

信号集操作函数

对于sigset_t信号集,我们不清楚里面有什么;不能直接对信号集进程操作,需要用到特定的函数接口。

在这里插入图片描述

相关信号集操作函数,例如初始化sigemptyset(设置为0)、sigfillset(设置为1)、sigaddset(新增信号)、sigdelset(删除信号)等等。

初始化信号集

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);

对于初始化信号集,分为两种:一是所有bit位设置为0、二是所有bit位设置为1

sigemptyset,初始化信号集,所有bit位设置为0

sigfillset,初始化信号集,所有bit位设置为1

新增信号

int sigaddset(sigset_t* set, int signum);

在信号集中,新增一个信号signum

删除信号

int sigdelsets(sigset_t* set, int signum);

在信号集set这,删除信号signum

对于上述的sigemptysetsigfilletsigaddsetsigdelset,这些函数返回值:

如果函数调用成功,返回0

函数调用失败,返回-1

判断信号是否存在

int sigismember(sigset_t* set, int signum);

sigismember函数用来判断信号集sig中是否存在信号signum

如果存在就返回1;如果不存在就返回0;如果函数调用失败就返回-1

系统调用

上述信号集操作函数,是修改当前已有信号集sigset_t

而在Linux内核中,存在block表和pending表来记录进程对于信号的屏蔽和未决状态;那我们能否修改内核中的block表呢?能否获取内核中的blockpending表呢?

当然是可以的,我们可以通过系统调用sigprocmasksigpending来对内核中进程的阻塞信号集未决信号集进行相关操作。

sigprocmask

调用该函数,可以修改或者读取信号屏蔽字

int sigprocmask(int how, const sigset_t *_Nullable restrict set, sigset_t *_Nullable restrict oldset);

对于sigprocmask函数,一共存在三个参数:

第一个参数表示要对内核中的block(阻塞信号集)进行什么操作;how的取值如下图:

在这里插入图片描述

第二个参数set指向当前信号集,我们需要自己创建信号集;

第三个参数oldset是一个输出型参数,当调用sigprocmask修改内核阻塞信号集时,会将内核阻塞信号集输出到oldset指向的信号集中。

测试:这里简单调用setprocmask为进程添加屏蔽2号信号

#include <stdio.h>
#include <signal.h>
#include <iostream>int main()
{sigset_t set;sigemptyset(&set);//初始化信号集sigaddset(&set, 2);//在信号集中添加2号信号sigset_t oldset;sigprocmask(SIG_BLOCK, &set, &oldset);while (true){}return 0;
}

在这里插入图片描述

sigpending

int sigpending(sigset_t *set);

调用sigpending函数可以获取进程的pending表(未决信号集)。

在内核中pending表是记录进程2未决信号的状态的,给进程发信号的本质就是修改内核中进程的pending表。

在获取了进程的未决信号集之后,我们可以使用信号集相关操作函数来判断该信号集中是否存在未决的信号。

这里简单验证:阻塞的信号是不会被递达的;

void print_pending()
{// 获取pendingsigset_t set;sigpending(&set);//输出位图for (int i = 31; i >= 1; i--){if (sigismember(&set, i))std::cout << '1';elsestd::cout << '0';}std::cout << std::endl;
}
void handler(int sig)
{std::cout << "receive sig : " << sig << std::endl;
}int main()
{//自定义捕捉2号信号signal(2, handler);//屏蔽2号信号sigset_t set, oldset;sigemptyset(&set);sigaddset(&set,2);sigprocmask(SIG_BLOCK, &set, &oldset);int cnt = 10;while(cnt--){//输出pending表print_pending();if(cnt == 0){//解除对2号信号的屏蔽sigemptyset(&set);sigprocmask(SIG_SETMASK, &oldset,nullptr);}sleep(1);}return 0;
}

在这里插入图片描述

总结

简单总结上述内容:

信号保存:block信号屏蔽表、pending信号未决表、handler信号处理方式(函数指针表)

信号集sigset_t,相关操作:初始化、新增、删除、判断是否存在等等

系统调用:sigprocmask:获取或设置内核blcok表、sigpending获取内核pending表。

http://www.lryc.cn/news/587940.html

相关文章:

  • 核电概念盘中异动,中核科技涨停引领板块热度
  • 机器学习/深度学习训练day1
  • 穿透、误伤与回环——Redis 缓存防御体系的负向路径与治理艺术
  • VirtualBox 安装 CentOS7 后无法获取 IP 的排查与修复
  • mysql 与redis缓存一致性,延时双删 和先更新数据库,再删除缓存,哪个方案好
  • 深浅拷贝以及函数缓存
  • 机床自动化中的“方言翻译官”:EtherNet/IP 转 PROFIBUS DP 实战手记
  • Redis作缓存时存在的问题及其解决方案
  • TensorFlow深度学习实战(26)——生成对抗网络详解与实现
  • 聚宽sql数据库传递
  • sqlserver迁移日志文件和数据文件
  • pytorch小记(二十九):深入解析 PyTorch 中的 `torch.clip`(及其别名 `torch.clamp`)
  • linux 驱动的platform机制:
  • SQL ORM映射框架深度剖析:从原理到实战优化
  • SPL 轻量级多源混算实践
  • Redis集群方案——Redis分片集群
  • Linux 消息队列接收与处理线程实现
  • python的微竞网咖管理系统
  • P2802 回家
  • 国家互联网信息办公室关于发布第十二批深度合成服务算法备案信息的公告
  • 力扣算法--数青蛙与外观数列问题
  • 3.2 WPF 画散点图
  • 【Python3教程】Python3高级篇之MySQL - mysql-connector 驱动介绍及示例
  • 【WPF】WPF 自定义控件 实战详解,含命令实现
  • 深地之下的智慧触角:Deepoc具身智能如何为矿业机器人铸就“感知之核”
  • Mac (m1) Java 加载本地C共享库函数 .dylib 函数 Unable to load library ‘liblicense‘
  • 【爬虫】Python实现爬取京东商品信息(超详细)
  • 来时路,零帧起手到Oracle大师
  • FilterRegistationBean报错does not have type parameters。idea启动日志无明显报错提示冲突 kaki的博客
  • IDEA实现纯java项目并打包jar(不使用Maven,Spring)