linux---信号的捕捉和处理

news2024/12/24 9:01:37



提示:以下是本篇文章正文内容,下面案例可供参考

一、信号

可以简单理解为信号是一个进程给另一个信号发消息,进程收到对应的信号就执行对应的方法,linux信号可以分为实时信号和非实时信号

1-31为非实时信号,34-64为实时信号,t它们是宏定义,写数字或者信号名称都可以,不过1-31号信号大部分都是中止进程,用命令:man 7 signal可查看信号的作用

特点:信号的产生是随机性,非实时信号可以被进程临时保留,到合适的时候处理

二、信号的捕捉和处理

1.signal()

用系统函数signal捕捉信号,通过回调函数处理信号。 以前如果进程收到信号,就会执行系统对应的方式处理信号,但是我们通过这个函数,可以捕捉特定信号,自定义处理信号,以下例子,参数为2号信号中止进程,进程收到2号信号,信号被捕捉,执行handsingle函数然后调用exit(0)中止进程。

没有收到2号信号就不会执行方法

我们也可以忽略这个信参数为SIG_IGN .忽略这个信号是进程收到这信号特殊处理

2.sigaction()

#include <signal.h>

int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);

signo 是捕捉的信号,act是一个结构体,我们设置是非实时信号,所以只要设置如下参数,用函数sigaddset添加要要堵塞的信号到sa_mask.

这里我们可以看到现象是,如果我们发送2号信号,那么就执行hanlder方法,执行方法过程中如果进程还收2号信号,那么就会对2号信号进行堵塞。我们发送3和4号(sa_mask),也会堵塞pending一直为1.

三.信号的发生方式:

1.键盘(硬件)

如果对一个进程失去控制ctrl+C或者ctrl+/,中止这个进程,Linux就会发送SINGINT/SINGQUITG给进程。

硬件到软件:cpu中有很多引脚,键盘按下触发高电平硬件中断,cpu内的寄存器就会记录下中断号,系统通过寄存器再通过中断向量表(实际是一个函数指针数组),执行读取方法,如果是普通字符就读取数据到文件缓冲区,识别是ctrl+/等就会发生信号给进程。

2.命令行

kill 杀死进程:kill -9 pid

实际上是封装了kill()系统函数

3.系统函数

kill/raise/abort():kill()可以杀死任意进程,raise哪个进程调用就给自己发信号(中止),abort()中止进程

4.异常

例如除零异常,野指针

除零异常:cpu寄存器计算的时候,如果出现除零异常就会将状态寄存器置为1,操作系统就会发信号给进程。

野指针:linux中通过页表的将虚拟地址映射到物理地址,虚拟地址转化为物理地址,是通过硬件MMU转换,转化失败,就会有寄存器记录信息,系统通过寄存器的状态发生信号给进程

5.软件条件

1.管道

比如说以2个进程分别读写方式打开管道,如果读端关闭,那么写端的进程就会收到信号就会退出,如果读端在管道没有读取到数据同时写端打开还没写,那么读端就会收到信号进行堵塞等待,直到管道中有数据。

2.alarm()定时器

alarm()中设置秒数,时间到了就会发 SIGALRM信号给进程,它的返回值是剩余时间的秒数,如果设置5秒,在这个期间又设置了2秒,闹钟提前了,这时就会返回3。(5秒时间没到,2秒的时候闹钟提前了),alarm(0)是取消之前设定的闹钟

四.信号的保存

1.修改block

一个进程的地址空间中维护3张表,进程收到信号实际是操作系统修改进程的表数据,block是堵塞状态位图,pending是未决状态位图,handler是信号的处理方式,是类型是一个函数指针。内核提供了信号集操作函数.

#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);//判断pending位是否为1.
函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有
效信号。
函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系
统支持的所有信号。
注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的
状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信

  

sigset_t是一个结构体类型,block和pending数据是1或0,linux用sigset_t结构体类型来表示,

#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);返回值:若成功则为0,若出错则为-1。

这个是how的参数,决定是否对信号进行堵塞或者解除堵塞状态,set是你添加的block,old是原来的block(通过它可以拿到之前的)


   sigset_t newblock,oldblock;
   //初始化block
   sigemptyset(&newblock);
   sigemptyset(&oldblock);
   //添加2信号(堵塞)
   //sigaddset(&newblock,2);

   //设置当前进程的block,屏蔽2号信号
   sigprocmask(SIG_SETMASK,&newblock,&oldblock);

 ,我们可以用这个函数堵塞一些信号,不过不是所有信号都可以屏蔽,比如9号信号或19。对信号进程堵塞,如果进程收到我们堵塞的信号,那么对应的pending一直是1,那它也不会执行handler方法,除非解除堵塞

2.pending的获取

pending表的获取,linux提供了系统函数判断是否信号是否未决。

3.信号的丢失

如果父进程同时收到 大量的子进程退出的信号(来不及处理覆盖了),那么它只会保留一个,父进程回收的时候就会造成大量的僵尸进程,

1.父进程等待回收

(1)堵塞式等待和非堵塞 式等待。

堵塞等待:不好的地方是,进程很多的话,有的进程不退出,那么它无法回到主进程。

非堵塞等待:子进程退出,那么会通知父进程进行回收,如果没有进程退出就会 结束等待。

2.直接忽略信号,进程退出不会造成僵尸进程

五,信号的处理时机

内核态和用户态:

当出现中断或者系统调用进程调度,就会进入内核态,处理完中断或者异常就会处理当前进程的收到的信号。如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 用户程序注册了SIGQUIT信号的处理函数sighandler。 当前正在执行main函数,这时发生中断或异常切换到内核态。 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函 数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是 两个独立的控制流程。 sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行

六,关键字volatile

从内存中读取数据,而不是因为编译器优化的原因,从寄存器中读取

int flag = 0;
//volatile int flag = 0
void handler(int sig)
{
printf("chage flag 0 to 1\n");
flag = 1;
}
int main()
{
signal(2, handler);
while(!flag);
printf("process quit normal\n");
return 0;
}

标准情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 , while 条件不满足,退出循环,进程退出,但是编译器优化后,将内存中的flag放入寄存器中,自定义动作修改了内存但是寄存器中并没有,进程不退出,关键字可以避免优化。

七.不可重入函数

例子:链表的插入:mian函数调用这个函数对全局链表进行插入操作,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为 不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数。。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安全风险 - 检测Android设备系统是否已Root

在很多app中都禁止 root 后的手机使用相关app功能&#xff0c;这种场景在金融app、银行app更为常见一些&#xff1b;当然针对 root 后的手机&#xff0c;我们也可以做出风险提示&#xff0c;告知用户当前设备已 root &#xff0c;谨防风险&#xff01; 最近在安全检测中提出了一…

远动通讯屏柜的组成及各装置的作用

远动通讯屏柜的组成及各装置的作用 远动通讯屏是基于公共电网安全而投入的远方监控遥控设备&#xff1b;主要由远动装置、通讯管理机、交换机、调制解调器、GPS对时装置、数字通道防雷器、模拟通道防雷器、插线板、空气开关、屏柜及附件等设备组成、标配尺寸2260*800*600&…

Android App启动流程和源码详解

前言 之前看了些App启动流程的文章&#xff0c;但是看得很浅显&#xff0c;隔了没多久就忘了&#xff0c;自己抓耳挠腮的终于看完了&#xff0c;看得头疼哦。因为很多是个人理解&#xff0c;大哥们主打一个7分信&#xff0c;2分思考&#xff0c;1分怀疑哈。 主要看的源码是An…

Python中文件操作和异常处理

文章目录 一、文件操作1.概念2.文件3.二进制 二、基本文件操作三、乱码产生四、with open() as f五、代码实现文件复制粘贴六、try ... except ...七、代码比较 一、文件操作 1.概念 帮助我们把爬虫抓下来的数据&#xff0c;进行保存。 2.文件 在计算机中&#xff0c;没有p…

工业大模型带来智能生产新范式

在当前工业行业的发展背景下&#xff0c;大模型技术展现出广阔的应用前景&#xff0c;在提升专业知识的可获取性和传承、优化软件技术的应用、提高数据驱动决策的准确性和效率等方面拥有显著潜力。 ‍‍‍‍‍‍‍‍‍‍据了解&#xff0c;蓝卓“基于supOS工业操作系统的工业大…

【HCIP学习】STP协议

一、STP协议出现背景&#xff08;Spanning Tree Protocol&#xff0c;生成树协议&#xff09; 二层环路带来的问题&#xff1a;广播风暴&#xff1b; MAC地址表的震荡&#xff1b; 二、STP定义 stp是二层网络中用于消除环路的协议&#xff0c;通过阻断冗余链路来消除&#xff…

ganglia的安装使用

1.集群内分别安装epel-release依赖&#xff0c;更新yum源 sudo yum -y install epel-release 2&#xff0e;各节点上分别安装gmond sudo yum -y install ganglia-gmond 3.监控节点上安装gmetad和web(这里安装在node1上) sudo yum -y install ganglia-gmetad sudo yum -y insta…

关于阳光雨露外派联想的面试感想

最近在找工作&#xff0c;接到了一个阳光雨露外派联想的面试邀请。说实在的一开始就有不对劲的感觉。想必这就是大厂的自信吧&#xff0c;上就问能不能现场面试&#xff0c;然后直接发面试邀请。这时候我倒是没觉得有啥问题。 然后今天就去面试去了&#xff0c;住的比较偏&…

力扣HOT100 - 138. 随机链表的复制

解题思路&#xff1a; class Solution {public Node copyRandomList(Node head) {if(headnull) return null;Node p head;//第一步&#xff0c;在每个原节点后面创建一个新节点//1->1->2->2->3->3while(p!null) {Node newNode new Node(p.val);newNode.next …

jupyter notebook打开ipynb文件报错500

一开始能打开ipynb文件&#xff0c;但是内核挂掉了&#xff0c;显示如下图的报错 按照网上的教程卸载重装了jupyter 再启动jupyter notebook打开ipynb文件就报错500 网上教程说nbconvert要更新&#xff0c;重装之类的&#xff0c;我都试过了&#xff0c;仍然报错 最后安了个P…

1103 缘分数(测试点4)

solution 测试点4&#xff1a;1 1不符合缘分数定义&#xff0c;但是这个判断能够通过记得排除掉 #include<iostream> #include<cmath> using namespace std; bool judge(int n){int t sqrt(n);if(t * t n) return true;return false; } int main(){int n, m, c…

Deep Residual Learning for Image Recognition--论文笔记

论文笔记 论文来源&#xff1a; Deep Residual Learning for Image Recognition 代码来源 还没上传 1论文摘要的翻译 深度神经网络更难训练。我们提出了一个残差学习框架&#xff0c;以简化比以前使用的网络深度大得多的网络的训练。我们明确地将层重新表述为参考层输入的…

概念艺术3D三维虚拟展览系统让更多人一同领略艺术的无穷魅力

经过多年的技术积累&#xff0c;华锐视点3D云展平台为各位提供的网上3D书画展厅&#xff0c;是一个集逼真视觉体验与沉浸式感官享受于一体的线上艺术殿堂。通过先进的Web3D实时渲染技术&#xff0c;打造全景3D立体场景&#xff0c;让您仿佛置身于实体展厅之中&#xff0c;感受那…

报名倒计时两周|2024 OpenTiny 开源之夏项目直播解读回顾

5月16日&#xff0c;OpenTiny 开源社区成功举办了以《OpenTiny 开源之夏项目解读直播》为主题的直播活动。此次直播中&#xff0c;华为云的高级前端工程师曾令卡、华为云的高级前端工程师伍其和与10位开源之夏技术专家携手组成项目导师团&#xff0c;面向广大开发者一同深入探讨…

QT加载CAD文件(一)QCAD

近期为了加载.dxf格式的文件简单学习了下QCAD和LibreCAD编译和二次开发&#xff0c;QCAD 是一个免费、开源的计算机辅助绘图二维工具, 目前开源的二维CAD有QCAD、LibreCAD等&#xff0c;LibreCAD可以说是QCAD的分支版本。 一、QCAD 官网网址&#xff1a;https://www.qcad.org…

spring boot整合j2cache 关闭二级缓存

我们整合了 j2cache 的项目启动 日志会输出 一级缓存 二级缓存 一级是 EhCacheProvider 二级是 SpringRedisProvider 如果 我们不想用二级缓存 在 j2cache.properties 中 加上 j2cache.12-cache-open配置 值为 true/false true是启用二级缓存 false 是不起用 默认 true 所以 …

低价焕新用户体验生态 京东向上增长通道宽了

5月16日&#xff0c;京东对外发布了其2024年第一季度财报。整体来看&#xff0c;相当不错&#xff0c;营收与净利润双双超预期。一季度&#xff0c;京东集团收入达到2,600亿元人民币&#xff08;约360亿美元&#xff09;&#xff0c;同比增长7.0%&#xff0c;尤其是在持续补贴和…

Golang net/http标准库常用方法(三)

大家好&#xff0c;针对Go语言 net/http 标准库&#xff0c;将梳理的相关知识点分享给大家~~ 围绕 net/http 标准库相关知识点还有许多章节&#xff0c;请大家多多关注。 文章中代码案例只有关键片段&#xff0c;完整代码请查看github仓库&#xff1a;https://github.com/hltfa…

工具分享:VsCode注释神器,koro1FileHeader

他是有官方Wiki的。 https://github.com/OBKoro1/koro1FileHeader/wiki/ 项目在GitHub上开源。以下摘录部分wiki&#xff0c;用作介绍分享在这里插入代码片 如何找到setting.json设置模板 简单的输入命令 打开VSCode命令面板: mac: command p window: ctrl p输入> Ope…