Linux信号——信号的处理(3)

信号是什么时候被处理?

进程从内核态,切换到用户态的时候,信号会被检测处理。
内核态:操作系统的状态,权限级别高
用户态:你自己的状态

内核态和用户态

进程地址空间第三次
所谓的系统调用本质其实是一堆函数指针数组。
1.我们使用系统调用或者访问系统数据,其实还是在我们进程的地址空间内进行跳转的。

2.进程无论如何切换,总能找到OS
我们访问OS,本质是通过我的进程的地址空间的[3,4]GB来访问的。
在这里插入图片描述

3.操作系统是如何运行的
信号技术本来就是通过软件的方式,来模拟的硬件中断
OS的周期时钟中断:非常高的频率,非常短的时间,给CPU发送中断——CPU不断进程处理中断。
操作系统是一个死循环,不断在接受外部的其他硬件中断。

4.操作系统不相信任何用户
必须要能区分当前用户的运行模式,所以就有了用户态和内核态。

信号是如何被处理?

在这里插入图片描述

捕捉信号还有其他方式吗?

#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数说明
signum: 要操作的信号编号(如 SIGINT、SIGTERM 等)
act: 指向新信号动作结构的指针,如果为 NULL 则不改变当前处理方式
oldact: 输出型参数,用于保存原信号动作结构的指针,如果为 NULL 则不保存
返回值
成功时返回 0,失败时返回 -1 并设置 errno。

struct sigaction {void     (*sa_handler)(int);         // 信号处理函数void     (*sa_sigaction)(int, siginfo_t *, void *); // 替代的信号处理函数sigset_t sa_mask;                    // 执行处理函数时要阻塞的信号int      sa_flags;                   // 修改行为的标志void     (*sa_restorer)(void);       // 已废弃
};

关于sa_mask变量

  1. 当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字(屏蔽该信号)
  2. 如果我们处理完对应的信号,该信号默认也会从信号屏蔽字中进行移除。(解除屏蔽该信号)
    为什么会这样?原因:不想让信号,嵌套式地对同一个信号进行捕捉处理。

用例子解释:

#include<iostream>
#include<signal.h>
void Print(sigset_t pending)
{std::cout<<" curr process pending: ";for(int sig = 31;sig > 0;sig--){if(sigismember(&pending,sig)) std::cout << "1";else std::cout <<"0";}std::cout << std::endl;
}
void handler(int signo)
{std::cout << "signal: " << signo <<std::endl;//不断获取当前进程的pending信号集并打印sigset_t pending;sigemptyset(&pending);while(true){sigpending(&pending);Print(pending);sleep(1);}
}int main()
{struct sigaction act,oact;act.sa_handler = handler;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaction(2,&act,&oact);while(true)sleep;
}

在这里插入图片描述

在调用信号处理函数时,除了当前信号被自动屏蔽外,还希望自动屏蔽另外一些信号,则要用sa_mask字段说明。
例子:

int main()
{struct sigaction act,oact;act.sa_handler = handler;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaddset(&act.sa_mask,3);sigaddset(&act.sa_mask,4);sigaddset(&act.sa_mask,5);//除了屏蔽当前正在处理的函数,还屏蔽3,4,5号信号sigaction(2,&act,&oact);while(true)sleep;
}

子进程信号版的进程退出

子进程退出,父进程不wait,子进程就会僵尸。
子进程退出,不是默默退出的,会在退出的时候,向父进程发送信号(17.SIGHLD
如何证明?

#include<iostream>
#include<signal.h>
#include<unistd.h>
void handler(int signo)
{std::cout <<"child quit, father get a signo: "<< signo << std::endl;
}
int main()
{signal(SIGCHLD,handler);pid_t id = fork();if(id == 0){//childint cnt = 5;while(cnt--){std::cout<<"I am child process: "<<getpid()<<std::endl;sleep(1);}std::cout<<"child process died"<<std::endl;exit(0);}//fatherwhile(true) sleep(1);return 0;
}

结果:确实子进程退出时向父进程发送了17号信号
在这里插入图片描述
所以当子进程退出时,发送17号信号,刚好我们将信号进行捕获,自定义处理信号,将该子进程进行回收,就有如下代码。

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>void handler(int signo)
{std::cout <<"child quit, father get a signo: "<< signo << std::endl;
}void CleanupChild(int signo)
{//v1// if(signo == SIGCHLD)// {//     pid_t rid = waitpid(-1,nullptr, 0);//-1表示任意一个子进程//     if(rid >0)//     {//         std::cout << "wait child success: " << rid << std::endl;//     }// }//v2-同时退出一百个进程// if(signo == SIGCHLD)// {// //但是如果同时要回收100个子进程,这时pending位图中在短时间内只能保存一次信号,所以加上循环,不停的回收//     while(true)//     {//         pid_t rid = waitpid(-1,nullptr, 0);//-1:表示任意一个子进程//         if(rid >0)//         {//             std::cout << "wait child success: " << rid << std::endl;//         }//         else if(rid <= 0) break;//     }// }//v3-50个进程退出,50个进程没有退出if(signo == SIGCHLD){//但是如果同时要回收100个子进程,这时pending位图中在短时间内只能保存一次信号,所以加上循环,不停的回收while(true){pid_t rid = waitpid(-1,nullptr, WNOHANG);//-1:表示任意一个子进程//以非阻塞方式等待if(rid >0){std::cout << "wait child success: " << rid << std::endl;}else if(rid <= 0) break;}}std::cout <<"wait sub process done"<<std::endl;
}
int main()
{signal(SIGCHLD,CleanupChild);pid_t id = fork();if(id == 0){//childint cnt = 5;while(cnt--){std::cout<<"I am child process: "<<getpid()<<std::endl;sleep(1);}std::cout<<"child process died"<<std::endl;exit(0);}//fatherwhile(true) sleep(1);return 0;
}

版本v1
特点

  1. 使用阻塞方式等待(options=0)
  2. 每次只能回收一个子进程

问题

  1. 如果有多个子进程同时退出,可能会丢失信号
  2. 阻塞调用可能会影响主程序执行

版本v2
改进

  1. 通过循环可以回收多个子进程,解决了多个子进程同时退出的问题。

问题

  1. 仍然是阻塞调用,如果子进程没有退出会一直阻塞。

版本v3
优点

  1. 使用 WNOHANG 非阻塞选项,不会阻塞主程序执行。
  2. 可以一次性回收所有已退出的子进程。

更简单的回收子进程的方式

直接忽略它,将SIGCHLD设置成SIG_IGN,即 signal(SIGCHLD,SIG_IGN);
这样子进程在终止时会被自动清理掉,不会产生僵尸进程,也不会通知父进程。
缺点:仅仅只是退出进程,无法通过自定义函数的方式获取子进程的id,退出码等相关信息。

:SIGCHLD的默认处理动作是IGN(忽略),为什么还要手动设置成SIG_IGN?
这是系统的一个特性,仅在Linux环境下。
设置系统层的IGN,进程终止时,会产生僵尸进程。
设置用户层的SIG_IGN,系统会将进程终止,不产生僵尸进程。

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

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

相关文章

MySQL篇(四)事务相关知识详解

MySQL篇(四&#xff09;事务相关知识详解 MySQL篇(四&#xff09;事务相关知识详解一、事务的特性&#xff08;ACID&#xff09;原子性&#xff08;Atomicity&#xff09;一致性&#xff08;Consistency&#xff09;隔离性&#xff08;Isolation&#xff09;持久性&#xff08;…

SpringBoot定时任务深度优化指南

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 SpringBoot定时任务深度优化指南 引言 在分布式系统架构中&#xff0c;定时任务是实现业务逻辑自动化的重要组件。SpringBoot通过Scheduled注解提供了便捷的…

MySQL表结构导出(Excel)

目录 一、java实现MySQL表结构导出&#xff08;Excel&#xff09; 二、python实现MySQL表结构导出&#xff08;Excel&#xff09; 又到了写毕设的时候了&#xff0c;计算机专业在写论文第四章系统设计的时候肯定会遇到和我一样的难题——要在论文中将数据库的表结构以表格形式…

Android使用OpenGL和MediaCodec渲染视频

目录 一&#xff0c;借助MediaCodec封装解码工具类VideoCodec 二&#xff0c;使用OpenGl绘制视频封装SoulFilter 一&#xff0c;借助MediaCodec封装解码工具类VideoCodec /*** 解码工具类* 解码完成后的数据 通过 ISurface 回调出去*/ public class VideoCodec {private ISu…

day39——输入操作:多值输入

数组输入&#xff1a; int main() {//***** 1、多值输入&#xff08;C&#xff09;/*输入&#xff1a;3 --> 3个值5 4 9*/int n;cin >> n; //输入个数const int MAX_SIZE 0xFFFF;//限定最大个数int a[MAX_SIZE];for (int i 0; i < n; i) {//用 n 作控制输入…

第九课:LoRA模型的原理及应用

文章目录 Part.01 3种LoRA的使用方式Part.02 5种LoRA的应用方向Part.01 3种LoRA的使用方式 LoRA能够在家用级设备上训练,实现对Checkpoint在某些方面的微调使用Lora的三种方式:放置Lora模型到目录中,然后作为提示词的一部分输入。点击生成按钮下面的“画”,然后打开Additio…

Cortex-M3 NVIC可以控制异常向量表的哪些部分

Cortex-M3 的 NVIC(嵌套向量中断控制器)不直接控制整个异常向量表,但可以管理向量表中与中断相关的部分行为。以下是 NVIC 对异常向量表的具体控制范围和相关机制: 1. NVIC 直接控制的部分 NVIC 主要管理 外部中断(IRQ) 和部分 系统异常 的行为,但对向量表本身的存储位…

双向链表增删改查的模拟实现

本章目标 0.双向链表的基本结构 1.双向链表的初始化 2.头插尾插 3.头删尾删 4.查找与打印 5.在指定位置之前插入数据/在指定位置之后插入数据 6.在指定位置之前删除数据/在指定位置之后删除数据 7.销毁链表 0.双向链表的基本结构 本章所实现的双向链表是双向循环带头链表,是…

实战交易策略 篇十四:江南神鹰捕捉热点和熊市生存交易策略

文章目录 系列文章捕捉热点是股市最大的掘金术市场温度不低于50是热点产生的必要条件题材的大小和新颖程度决定热点的持续时间和涨幅炒作热点的3个阶段捕捉热点的方法与步骤操作实战案例熊市生存术“熊市最好的做法是离开股市”的说法是一句空话熊市盈利模式:不轻言底部,超跌…

Linux错误(6)X64向量指令访问地址未对齐引起SIGSEGV

Linux错误(6)X64向量指令访问地址未对齐引起SIGSEGV Author: Once Day Date: 2025年4月4日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: Linux实…

解码 __iter__ 和 itertools.islice - 迭代的艺术

文章目录 前言一、`_iter__`:自定义迭代的钥匙1.1 什么是 __iter__?1.2 基本用法1.3 高级用法:独立迭代器二、itertools.islice:迭代切片的利器2.1 什么是 itertools.islice?2.2 基本用法2.3 处理无限序列2.4 实际应用三、`__iter__` 与 `islice` 的结合六、为什么需要它们…

使用VSCode编写C#程序

目录 一、环境搭建&#xff1a;构建高效开发基础1. 安装VSCode2. 配置.NET SDK3. 安装核心扩展 二、项目开发全流程1. 创建项目2. 代码编辑技巧3. 调试配置4. 高级调试技巧5. 编译与运行 三、常见问题解决指南1. 项目加载失败2. IntelliSense失效3. 代码格式化4. 典型编译错误&…

日本汽车规模性经济计划失败,日产三大品牌的合并合作共赢,还是绝地求生?本田与日产合并确认失败,将成为世界第三大汽车集团愿景失败

本田与日产(含三菱汽车)的合并计划最终因核心矛盾无法调和而宣告失败,这一事件揭示了传统车企在行业变革期的深层困境。以下从合并动机、失败原因、本质判断及未来影响等方面综合分析: 一、合并的初衷:生存压力主导的被动策略 市场危机与财务困境 中国市场溃败:日系品牌在…

AutoCAD2026中文版下载安装教程

AutoCAD是一款由Autodesk公司开发的计算机辅助设计软件&#xff0c;被广泛应用于建筑设计、机械设计、电气设计、土木工程、装饰装潢等多个领域。AutoCAD2026中文版在原有的基础上进行了多项改进和优化&#xff0c;为用户提供了更为高效、便捷的绘图和设计体验。这里我给大家分…

Latex语法入门之数学公式

Latex是一种高质量的排版系统&#xff0c;尤其擅长于数学公式的排版。本文我将带大家深入了解Latex在数学公式排版中的应用。从基础的数学符号到复杂的公式布局&#xff0c;我们都会一一讲解&#xff0c;通过本文的学习&#xff0c;你将能够轻松编写出清晰、美观的数学公式&…

洛谷 P3214 [HNOI2011] 卡农

题目传送门 前言 再次败在 d p dp dp 手下&#xff0c;但是数据范围这么小应该是可以看出是 d p dp dp 的&#xff08;毕竟对于其他组合数的问题数据范围都是 1 0 9 10^9 109 起步&#xff09;。 思路 题意简化 现有 1 , 2 , 3 , . . . , n − 1 , n 1, 2, 3, ... , n -…

【年份数据类型及使用】

在数据分析中,年份的处理需要根据具体场景选择合适的数据类型,以确保后续分析的准确性和效率。以下是常见的年份数据类型及使用场景: 1. 数值类型(整数或浮点数) 适用场景: 仅需存储年份数值(如 2020, 2023),无需进行日期计算。需要将年份作为连续变量参与数学运算(如…

详解七大排序

目录 一.直接插入排序 &#xff08;1&#xff09;基本思想 &#xff08;2&#xff09;算法步骤 &#xff08;3&#xff09;代码实现 &#xff08;4&#xff09;算法特性 &#xff08;5&#xff09;算法优化 &#xff08;6&#xff09;示例演示 二.希尔排序 &#xff08…

YOLOv12 训练从这里开始:LabelImg 标注数据集

视频讲解&#xff1a; YOLOv12 训练从这里开始&#xff1a;LabelImg 标注数据集 labelimg https://github.com/tzutalin/labelImg sudo apt-get install pyqt5-dev-tools pip3 install lxml git clone https://github.com/tzutalin/labelImg.git cd labelImg 开始编译 make…

Day2:前端项目uniapp壁纸实战

先来做一个轮番图。 效果如下&#xff1a; common-style.css view,swiper,swiper-item{box-sizing: border-box; } index.vue <template><view class"homeLayout"><view class"banner"><swiper circular indicator-dots autoplay…