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

Linux——进程信号(二)

引言

在进程信号(一)中我们已经讲到了信号的保存,那么接下来要讲信号的处理了。

信号的处理主要要回答3个问题:

1.信号什么时候被处理的?

2.信号如何被处理的?

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

首先回答问题一:信号在合适的时候被处理,那什么是合适的时候呢?

这就要先看什么是内核态和用户态了 

一、内核态和用户态

在这里先回答到底是什么时候:

进程从内核态切换回用户态的时候(CPU中有寄存器来专门标识执行状态),信号会被检测并处理

OS是一个进行软硬件资源管理的软件,它很容易就能获取到CPU中CR3寄存器中是0还是3,从而知道当前是用户态还是内核态 

1.1内核态和用户态的概念

用户态:一种用来执行普通用户代码的状态,是一种受监管的状态

内核态:通常用来执行OS的代码,是一种权限非常高的状态

执行系统调用时,是由操作系统来执行的,而不是用户。那么有引出了一个问题:一个进程又是怎么跑到OS中执行代码的呢?

 之前我们说地址空间[0,3]GB的用户空间,[3,4]GB是内核空间

用户所写的代码和数据位于用户空间为了保证进程的独立性,每个进程都有自己的进程地址空间,都有一个用户级页表

还有一份所有进程共用的内核级页表

进程地址空间的 3~4GB是不允许用户访问的,因为这1GB空间的代码和数据通过内核级页表和内存中的OS相映射。内存中只存在一份内核,所以所有进程的虚拟地址空间的那1G内核空间都通过同一份内核级页表映射到同一个内核

所以回答一下刚才的问题:进程又是怎么跑到OS中执行代码的呢?

1.进程使用系统调用或者访问系统数据,其实还是在进程的地址空间内进行跳转的

2.进程无论如何切换总能找到操作系统,我们访问操作系统本质就是通过进程的地址空间的[3,4]GB来访问

3.不同的进程指向同一张内核级页表,这样就都能进行系统调用

1.2内核态和用户态转化

用过系统调用->陷入内核->OS执行系统调用->结果给用户

 在处理信号的过程(捕捉) 中,一共会有4次状态切换(内核/用户态)

  1. 执行到用户代码中的系统调用函数时,会跳转到虚拟地址空间中的内核空间去执行对应的方法,此时陷入内核,状态从用户态变成内核态
  2. 当系统系统调用被执行完后,再返回之前,OS会检查task_struct中的两张位图表,然后根据handler表中的处理方式去处理相应的信号,如果此时是自定义的处理方式,那么OS会用这handler表中此自定义函数的地址去执行用户自定义的处理方式,此时状态从内核态转化为用户态
  3. 在执行完信号处理函数后,返回时会执行特殊的系统调用,再次进入内核,此时状态从用户态变成内核态
  4. 特殊系统调用执行完返回用户模式,返回用户代码原来的位置继续向下执行,此时状态从内核态转化为用户态

为什么我们在信号捕捉的时候,执行我们写的方法(自定义),还要从内核态切换到用户态?(用户态执行方法)

OS不信任(用户),还是让用户去(在外面)用系统调用安全些(万一你的方法时一些越权的非法操作呢,操作系统还要继续执行吗)

二、处理信号sigaction

信号的捕捉除了前面用过的signal函数之外,我们还可以使用sigation函数对信号进行捕捉

man sigaction

sigaction函数可以读取和修改与指定信号相关联的处理动作,该函数调用成功返回0,出错返回-1

signum:指定信号的编号

若act指针非空,根据act修改该信号的处理动作

若oldact指针非空,则通过oldact传出该信号原来的处理动作 

act和oact指向sigaction结构体:

struct sigaction
{void(*sa_handler)(int);void(*sa_sigaction)(int,siginfo_t *,void *);sigset_t sa_mask;int sa_flags;void(*sa_restorer)(void);
};

对于sigaction结构体第一个成员来说:

将sa_handler赋值为

SIG_IGN传给sigaction函数,表示忽略此信号

 SIG_DFL,表示执行系统默认动作

一个函数指针,表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函数

 第二个成员是实时信号的处理函数,我们不讲

第三个:sa_mask

当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止。 如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。

第四、五个不讲

sigaction的使用:

将2号信号自定义捕捉,打印信号编号,设置sa_mask当2号递达后会被阻塞

#include<iostream>
#include<unistd.h>
#include<signal.h>
using namespace std;void Print(sigset_t &pending)
{cout<<"Pending bitmap: ";for (int signub = 31; signub > 0; signub--){if (sigismember(&pending, signub)){std::cout << "1";}else{std::cout << "0";}}std::cout << std::endl;
}void sigcb(int signo)
{cout<<"signal:"<<signo<<endl;sigset_t pending;sigemptyset(&pending);while(1){sigpending(&pending);Print(pending);sleep(1);}
}
int main()
{struct sigaction act,oact;act.sa_handler = sigcb;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaction(2,&act,&oact);while(true){sleep(1);}    return 0;
}

三、可重入函数

可重入函数:被不同执行流重复进入不会产生问题的函数

以链表的插入为例,当main函数(主执行流)的insert插入执行一半时,又来一个新信号自定义处理方法中又调用了insert函数->该函数被重复进入了(main执行流、信号捕捉执行流)->导致产生了问题:该函数叫做不可重入函数(我们用到的大部分函数都是不可重入的)

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

如果一个函数符合以下条件之一则是不可重入的:
调用了malloc或free,因为malloc也是用全局链表来管理堆的。
调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构

volatile关键字

volatile是C语言中的一个关键字,它的作用是保持内存的可见性

#include <stdio.h>
#include <signal.h>
int flag = 0;
void handler(int signo)
{cout<<"change flag:"<<flag;flag = 1;cout<<"->"<<flag<<endl;
}
int main()
{signal(2, handler);while(!flag);printf("process quit normal\n");return 0;
}

 在接收到2号信号后,quit从0变成1,main函数正常结束,不在循环

编译器又是会做很多优化,g++编译器可以指定优化级别 -O3是最高的优化级别

mytest:sigaction.ccg++ -o $@ $^ -std=c++11 -O3
.PHONY:clean
clean:rm -f mytest

 这时重新编译

 发送2好信号后进程没有退出。flag改为1,但是主执行流还在循环

当flag添加volatile关键字后

#include <stdio.h>
#include <signal.h>
volatile int flag = 0;
void handler(int signo)
{cout<<"change flag:"<<flag;flag = 1;cout<<"->"<<flag<<endl;
}
int main()
{signal(2, handler);while(!flag);printf("process quit normal\n");return 0;
}

进程正常结束了 

SIGCHLD信号

进程一章讲过用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻 塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞了就不 能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一下,程序实现复杂。
其实,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自 定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程 终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。


请编写一个程序完成以下功能:父进程fork出子进程,子进程调用exit(2)终止,父进程自定 义SIGCHLD信号的处理函数,在其中调用wait获得子进程的退出状态并打印。


事实上,由于UNIX 的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调 用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不 会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略 通常是没有区别的,但这是一个特例。此方法对于Linux可用,但不保证在其它UNIX系统上都可 用。请编写程序验证这样做不会产生僵尸进程。

相关文章:

Linux——进程信号(二)

引言 在进程信号(一)中我们已经讲到了信号的保存&#xff0c;那么接下来要讲信号的处理了。 信号的处理主要要回答3个问题&#xff1a; 1.信号什么时候被处理的&#xff1f; 2.信号如何被处理的&#xff1f; 3.捕捉信号还有其他方式吗&#xff1f; 首先回答问题一&#xff1…...

2024.5组队学习——MetaGPT(0.8.1)智能体理论与实战(下):多智能体开发

传送门&#xff1a; 《2024.5组队学习——MetaGPT&#xff08;0.8.1&#xff09;智能体理论与实战&#xff08;上&#xff09;&#xff1a;MetaGPT安装、单智能体开发》《2024.5组队学习——MetaGPT&#xff08;0.8.1&#xff09;智能体理论与实战&#xff08;中&#xff09;&…...

SQL开窗函数

文章目录 概念&#xff1a;语法&#xff1a;常用的窗口函数及示例&#xff1a;求平均值&#xff1a;AVG() &#xff1a;求和&#xff1a;SUM():求排名&#xff1a;移动平均计数COUNT():求最大MXA()/小MIN()值求分区内的最大/最小值求当前行的前/后一个值 概念&#xff1a; 开窗…...

[xx点评完结]——白马点评完整代码+rabbitmq实现异步下单+资料,免费

项目所有功能已测&#xff0c;均可以跑通&#xff0c;Jmeter和RabbitMQ也都测了。 项目源码:dianpinghui: 仿黑马点评项目 资料: https://pan.baidu.com/s/1kTCn9PxgeIey90WgM4KRqA?pwdn66b 对佬有帮助可以给个star哈&#xff0c;感谢&#x1f339;&#x1f339;&#x1f3…...

Hadoop+Spark大数据技术 实验8 Spark SQL结构化

9.2 创建DataFrame对象的方式 val dfUsers spark.read.load("/usr/local/spark/examples/src/main/resources/users.parquet") dfUsers: org.apache.spark.sql.DataFrame [name: string, favorite_color: string ... 1 more field] dfUsers.show() -----------…...

认知V2X的技术列一个学习大纲

为了深入学习和理解V2X&#xff08;Vehicle to Everything&#xff09;技术&#xff0c;以下是一个学习大纲的概述&#xff0c;结合了参考文章中的相关数字和信息&#xff1a; 一、V2X技术基础 V2X概述 定义&#xff1a;V2X是车用无线通信技术&#xff0c;将车辆与一切事物相连…...

揭秘齿轮加工工艺的选用原则:精准打造高效传动的秘密武器

在机械制造领域&#xff0c;齿轮作为传动系统中的重要组成部分&#xff0c;其加工工艺的选择至关重要。不同的齿轮加工工艺会影响齿轮的精度、耐用性和效率。本文将通过递进式结构&#xff0c;深入探讨齿轮加工工艺的选用原则&#xff0c;带您了解如何精准打造高效传动的秘密武…...

Linux-应用编程学习笔记(二、文件I/O、标准I/O)

一、文件I/O基础 文件 I/O 指的是对文件的输入/输出操作&#xff0c;就是对文件的读写操作。Linux 下一切皆文件。 1.1 文件描述符 在 open函数执行成功的情况下&#xff0c; 会返回一个非负整数&#xff0c; 该返回值就是一个文件描述符&#xff08;file descriptor&#x…...

AI爆文写作:根据别人的爆款标题,如何通过名词替换改成自己的爆款标题?

在日常刷到爆文的时候&#xff0c;就可以培养自己的网感&#xff0c;为啥这篇文章会爆&#xff1f; 这篇爆文的标题有啥诀窍呢&#xff1f; 比如下面这一篇&#xff1a;《极简生活&#xff1a;变富就是每天循环5个动作》 我们可以发现&#xff0c;每天循环5个动作 这几个词语…...

Mybatis源码剖析---第二讲

Mybatis源码剖析—第二讲 那我们在讲完了mappedstatement这个类&#xff0c;它的一个核心作用之后呢&#xff1f;那下面我有一个问题想问问各位。作为mappedstatement来讲&#xff0c;它封装的是一个select标签或者insert标签。但是呢&#xff0c;我们需要大家注意的是什么&am…...

SpringMvc-restful设计风格

Restful 1、入门1.1 简介1.2 实例 1、入门 1.1 简介 RESTFul是什么 RESTFul是WEB服务接口的一种设计风格。 RESTFul定义了一组约束条件和规范&#xff0c;可以让WEB服务接口更加简洁、易于理解、易于扩展、安全可靠。 1.2 实例 web.xml <?xml version"1.0"…...

在未来你将何去何从?

在数字化的浪潮中&#xff0c;信息技术行业无疑是推动全球经济和社会发展的重要动力。随着科技的不断迭代与进步&#xff0c;云计算、大数据、人工智能&#xff08;AI&#xff09;、物联网&#xff08;IoT&#xff09;、5G通信和区块链等技术已经深入到我们生活的每一个角落&am…...

Vue.js组件设计模式:构建可复用组件库

在Vue.js中&#xff0c;构建可复用的组件库是提高代码复用性和维护性的关键。下面是一些设计模式&#xff0c;说明如何创建可复用的Vue组件&#xff1a; 1. 单文件组件&#xff08;Single File Component, SFC&#xff09; Vue.js组件通常是单文件组件&#xff0c;包含HTML、…...

【C语言】指针运算

前言 前面在“走进指针世界”中我已经讲解过指针相关的很多前置知识&#xff0c;其实还有一个很重要的部分就是指针的运算。这篇博客&#xff0c;就让我们一起了解一下指针的运算吧&#xff01; 指针作为变量&#xff0c;是可以进行算术运算的&#xff0c;只不过情况会和整型…...

Python学习(3) 函数

定义 定义一个函数的格式&#xff1a; def 函数名(参数):执行代码如果没有参数&#xff0c;则称为无参函数。 定义时小括号中写的是形参&#xff08;形式参数&#xff09;&#xff0c;调用时写的是实参&#xff08;实际参数&#xff09;。 调用 调用格式&#xff1a; def…...

计算机网络安全控制技术

1.防火墙技术 防火墙技术是近年来维护网络安全最重要的手段&#xff0c;但是防火墙不是万能的&#xff0c;需要配合其他安全措施来协同 2.加密技术 目前加密技术主要有两大类&#xff1a;对称加密和非对称加密 3.用户识别技术 核心是识别网络者是否是属于系统的合法用户 …...

WordPress插件Disable WP REST API,可根据是否登录来禁用REST API

前面跟大家分享了代码版禁用WordPress REST API的方法&#xff08;详见『WordPress4.7以上版本如何禁用JSON REST API&#xff1f;』&#xff09;&#xff0c;不过有些站长不太敢折腾自己的网站代码&#xff0c;那么建议试试这款Disable WP REST API&#xff0c;它可以&#xf…...

腾讯云COS上传文件出现的问题

1、没有配置 ObjectMetadata 的文件长度 腾讯云COS上传文件出现数据损坏问题_no content length specified for stream data. strea-CSDN博客 2、 使用 FileInputStream使用完没有及时关闭导致报错 ClientAbortException: java.nio.channels.ClosedChannelException 添加…...

【C++】<知识点> 标准和文件的输入输出

目录 一、输入输出操作 1. 相关的类 2. 标准流对象 3. istream类的成员函数 二、流操纵算子 1. 整数流的基数 2. 浮点数精度的流操纵算子 3. 域宽的流操纵算子 4. 其他的流操纵算子 5. 用户自定义流操纵算子 三、文件读写 1. 文本文件的读写 2. 二进制文件的读写 3. 文件读写…...

在阿里Anolis OS 8.9龙蜥操作系统安装docker

在Anolis OS 8系统安装docker 1.更新系统 sudo dnf update -y2.安装依赖包 sudo dnf install -y yum-utils device-mapper-persistent-data lvm23.添加Docker的官方仓库 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo4.安装…...

OpenClaw 深度研究报告:从开源框架到企业级智能体平台的演进之路

一、核心定位&#xff1a;突破"对话天花板"的执行中枢 OpenClaw&#xff08;外号"龙虾"&#xff09; 是由奥地利工程师 Peter Steinberger 于 2025 年底开发的本地优先、模型无关的 AI 智能体运行框架。其核心价值主张极为鲜明&#xff1a; “The AI that …...

告别答辩 PPT 熬夜局!PaperXie AI 一键生成,3 分钟拿捏学术范答辩神器

paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AIPPThttps://www.paperxie.cn/ppt/createhttps://www.paperxie.cn/ppt/create 一、开题答辩人破防瞬间&#xff1a;PPT 做得好&#xff0c;答辩分数高一半 “论文写完了&#xff0c;PPT 才是真正的修罗场…...

人肉区块链:用群体记忆对抗AI篡改

当测试数据面临AI篡改危机在生成式AI全面渗透软件开发生命周期的今天&#xff0c;软件测试从业者正面临前所未有的挑战。AI工具在提升测试用例生成、缺陷预测和日志分析效率的同时&#xff0c;也带来了隐蔽而致命的风险&#xff1a;AI驱动的数据篡改。自动化测试结果被注入虚假…...

实战应用:基于快马平台开发具备origin高级分析功能的在线工具

今天想和大家分享一个最近用InsCode(快马)平台做的实战项目——开发一个具备Origin高级分析功能的在线工具。作为一个经常需要处理实验数据的科研狗&#xff0c;Origin这类软件的分析功能确实强大&#xff0c;但每次都要安装本地软件实在麻烦。于是就想试试能不能做个在线版&am…...

Qwen3.5-2B轻量化技术解析:模型剪枝+KV Cache优化如何降低70%显存占用

Qwen3.5-2B轻量化技术解析&#xff1a;模型剪枝KV Cache优化如何降低70%显存占用 1. 轻量化模型的核心价值 在AI模型部署领域&#xff0c;大模型的资源消耗一直是阻碍其广泛应用的瓶颈。Qwen3.5-2B作为一款仅20亿参数的多模态基础模型&#xff0c;通过创新的轻量化技术实现了…...

Axure 9.0 原生组件:绘制折线图

引言在原型设计中&#xff0c;数据可视化是传递核心信息的关键手段&#xff0c;而折线图凭借 “清晰展示数据趋势” 的优势&#xff0c;广泛应用于销售波动、用户增长、指标变化等场景。Axure 9.0 作为主流原型工具&#xff0c;虽未内置现成折线图组件&#xff0c;但通过「形状…...

3步搞定大麦网自动抢票:告别手速不够的时代

3步搞定大麦网自动抢票&#xff1a;告别手速不够的时代 【免费下载链接】Automatic_ticket_purchase 大麦网抢票脚本 项目地址: https://gitcode.com/GitHub_Trending/au/Automatic_ticket_purchase 还在为抢不到心仪演唱会门票而烦恼吗&#xff1f;当周杰伦、五月天等热…...

京东抢购自动化全攻略:从入门到精通的技术实践指南

京东抢购自动化全攻略&#xff1a;从入门到精通的技术实践指南 【免费下载链接】JDspyder 京东预约&抢购脚本&#xff0c;可以自定义商品链接 项目地址: https://gitcode.com/gh_mirrors/jd/JDspyder 30秒快速评估&#xff1a;你是否需要JDspyder&#xff1f; 在决…...

编程技巧:模式切换程序框架

目录 1.模式切换程序框架 2.实现思路 3.模式切换程序框架 4.模式切换每个模式模块化流程 5.代码 Mode1.c Mode2.c Mode3.c Global.c main.c 1.模式切换程序框架 Init&#xff1a;进入模式前&#xff0c;执行一遍&#xff0c;用于初始化工作 Loop&#xff1a;执行完In…...

STM32定时器时基单元详解:从PSC到ARR的完整配置指南(附代码)

STM32定时器时基单元实战指南&#xff1a;从寄存器配置到精准延时实现 在嵌入式开发中&#xff0c;定时器是最基础也最核心的外设之一。无论是简单的LED闪烁控制&#xff0c;还是复杂的电机PWM驱动&#xff0c;都离不开定时器的精准计时功能。对于STM32开发者来说&#xff0c;掌…...