【Linux】进程信号篇Ⅲ:可重入函数、volatile关键字、SIGCHLD信号
信号Ⅲ
- 🔗 接上篇
- 七、可重入函数
- 八、volatile 关键字
- 九、SIGCHLD 信号
🔗 接上篇
👉🔗进程信号篇Ⅰ:信号的产生(signal、kill、raise、abort、alarm)、信号的保存(core dump)
👉🔗进程信号篇Ⅱ:信号的阻塞及保存(sigset_t, sigprocmask, sigpending)、信号的处理、信号的捕捉(sigaction)
七、可重入函数
不同的执行流中,同一个函数被重复进入。
有的函数,在功能上,重新进入后会产生我们不想看到的结果,这样的函数叫 不可重入函数。
对于没有重入问题的函数,我们叫做 可重入函数(Reentrant)
例如:insert 函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入。
insert 函数访问一个全局链表,有可能因为重入而造成错乱。两个不同的控制流程 调用同一个函数 访问它的 **同一个局部变量或参数**,就是可重入的。
如果一个函数符合以下条件之一则是不可重入的:
-
调用了 malloc 或 free,因为 malloc 也是用全局链表来管理堆的。
-
调用了标准 I/O 库函数。标准 I/O 库的很多实现都以不可重入的方式使用全局数据结构。
八、volatile 关键字
volatile这个关键字,可以声明,让编译器每次都去内存中读取数据,可以保证内存的可见性。
#include <stdio.h>
#include <signal.h>/*volatile*/ int quit = 0; // 保证内存可见性void handler(int signo)
{printf("change quit from 0 to 1\n");quit = 1;printf("quit: %d\n", quit);
}int main()
{signal(2, handler);while(!quit); // 这里不携带代码块,故意让编译器认为在 main 中,quit 只做检测作用printf("main quit 正常\n");return 0;
}
在一些编译版本下,如此叫 while 不挟带代码块,可以让编译器对 只用作检测的 quit 做优化。原本每次都要从内存中 load 进 cpu 的寄存器中再进行判断计算,优化后,编译器认为 quit 只是检测用的,便直接把 quit 的值 load 进寄存器后每次直接从寄存器中读取数据。这种优化就导致了内存不可见。
对上述代码 quit 进行 volatile 声明,就表示,要求编译器每次都要从内存里去重新读取数据。不让直接使用寄存器中的数据,保证内存数据可见。
九、SIGCHLD 信号
进程一章讲过用 wait 和 waitpid 函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。
采用第一种方式,父进程阻塞了就不能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一下,程序实现复杂。
其实,子进程在终止时会给父进程发 SIGCHLD 信号,该信号的默认处理动作是 忽略,父进程可以自定义 SIGCHLD 信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用 waitpid 清理子进程即可。
🌰代码举例:父进程 fork 出子进程,子进程调用 exit(1) 终止,父进程自定义 SIGCHLD 信号的处理函数,在其中调用 wait 获得子进程的退出状态并打印。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>pid_t id;void waitprocess(int signo)
{printf("我:%d ,捕捉到一个信号:%d\n",getpid(),signo);sleep(5); // 这期间,子进程将处于 僵尸状态// 实现:只将部分退出的回收,没有退出需求的不处理while(1){ // 如果 WNOHANG 位置填 0,会导致,遇到没有退出的子进程时,就 hang 住了,没法往下继续运行// WNOHANG 意在,有的话给退出,没有的话就返回pid_t res = waitpid(-1, NULL, WNOHANG); // -1 代表回收任意一个子进程if(res > 0){printf("wait success,res: %d, id: %d\n", res, id);}else break; // 如果没有子进程了就 break}printf("handler done...\n");
}int main()
{signal(SIGCHLD, waitprocess);int i = 1;for(; i <= 10; i++){id = fork();if(id == 0){int count = 5;while(count){printf("我是子进程,我的 pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);count--;}exit(1);}}while(1){sleep(1);}return 0;
}
如果父进程没啥事要干,可以在下面 waitpid
如果父进程很忙,而且不退出,可以选择信号的方式
事实上,由于 UNIX 的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调用 sigaction 将 SIGCHLD 的处理动作置为 SIG_IGN,这样 fork 出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。
系统默认的忽略动作和用户用 sigaction 函数自定义的忽略通常是没有区别的,但 这是一个特例。此方法对于 Linux 可用,但不保证在其它 UNIX 系统上都可用。
🌰总之,上面的代码可以改写成这样:
int main()
{//signal(SIGCHLD, waitprocess);sigaction(SIGCHLD, SIG_IGN);int i = 1;for(; i <= 10; i++){id = fork();if(id == 0){int count = 5;while(count){printf("我是子进程,我的 pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);count--;}exit(1);}}while(1){sleep(1);}return 0;
}
🥰如果本文对你有些帮助,请给个赞或收藏,你的支持是对作者大大莫大的鼓励!!(✿◡‿◡) 欢迎评论留言~~
相关文章:
【Linux】进程信号篇Ⅲ:可重入函数、volatile关键字、SIGCHLD信号
信号Ⅲ 🔗 接上篇七、可重入函数八、volatile 关键字九、SIGCHLD 信号 🔗 接上篇 👉🔗进程信号篇Ⅰ:信号的产生(signal、kill、raise、abort、alarm)、信号的保存(core dump&#x…...
排序算法:冒泡排序
冒泡排序是入门级的算法,但也有一些有趣的玩法。通常来说,冒泡排序有三种写法: 一边比较一边向后两两交换,将最大值 / 最小值冒泡到最后一位;经过优化的写法:使用一个变量记录当前轮次的比较是否发生过交换…...
Spring事件监听源码解析
spring事件监听机制离不开容器IOC特性提供的支持,比如容器会自动创建事件发布器,自动识别用户注册的监听器并进行管理,在特定的事件发布后会找到对应的事件监听器并对其监听方法进行回调。Spring帮助用户屏蔽了关于事件监听机制背后的很多细节…...
Cpp学习——list的模拟实现
目录 一,实现list所需要包含的三个类 二,三个类的实现 1.list_node 2.list类 3.iterator_list类 三,功能实现 1.list类里的push_back() 2.iterator类里的运算符重载 3,list类里面的功能函数 1.insert(ÿ…...
工具推荐:Chat2DB一款开源免费的多数据库客户端工具
文章首发地址 Chat2DB是一款开源免费的多数据库客户端工具,适用于Windows和Mac操作系统,可在本地安装使用,也可以部署到服务器端并通过Web页面进行访问。 相较于传统的数据库客户端软件如Navicat、DBeaver,Chat2DB具备了与AIGC…...
C语言刷题指南(二)
📙作者简介: 清水加冰,目前大二在读,正在学习C/C、Python、操作系统、数据库等。 📘相关专栏:C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 👍…...
[C++11]
文章目录 1. 自动类型推导1.1 auto1.1.1 推导规则1.1.2 auto的限制1.1.3 auto的应用1.1.4 范围for 1.2 decltype1.2.1 推导规则1.2.2 decltype的应用 1.3 返回类型后置 2.可调用对象包装器、绑定器2.1 可调用对象包装器2.1.1 基本用法2.1.2 作为回调函数使用 2.2 绑定器 3. usi…...
【MySQL系列】--初识数据库
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
Unity导入google.protobuf失败,无法找到google命名空间
问题: 1.刚开始把protobuf的文件夹直接从其他项目里(unity2021)里复制到unity(2020)版本,当时报错protobuf.dll的依赖项system.memory版本不对。 2.没有使用原来的protobuf文件了。使用vs2019的NuGet管理包来下载Google.Protobuf ,仍然报错找…...
使用IDM下载视频出现“由于法律原因,IDM无法下载...
一、问题描述 由于法律原因,IDM无法下载..,如图: 二、原因分析 下载该IDM抓取的M3U8文件,查看其中的内容发现 : #EXT-X-KEY 字段已经写明了加密方式是AES-128,包含一个URI和IV值 #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:8 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-KEY:…...
pointnet C++推理部署--tensorrt框架
classification 如上图所示,由于直接export出的onnx文件有两个输出节点,不方便处理,所以编写脚本删除不需要的输出节点193: import onnxonnx_model onnx.load("cls.onnx") graph onnx_model.graphinputs graph.inpu…...
34.Netty源码之Netty如何处理网络请求
highlight: arduino-light 通过前面两节源码课程的学习,我们知道 Netty 在服务端启动时会为创建 NioServerSocketChannel,当客户端新连接接入时又会创建 NioSocketChannel,不管是服务端还是客户端 Channel,在创建时都会初始化自己…...
vscode 安装勾选项解释
1、通过code 打开“操作添加到windows资源管理器文件上下文菜单 :把这个两个勾选上,可以对文件使用鼠标右键,选择VSCode 打开。 2、将code注册为受支持的文件类型的编辑器:不建议勾选,这样会默认使用VSCode打开支持的相…...
Spring 6.0官方文档示例(24): replace-method的用法
一、原始bean定义 package cn.edu.tju.study.service.anno.domain;public class MyValueCalculator {public String computeValue(String input) {return "you inputted: " input;}// some other methods... }二、replace bean定义 package cn.edu.tju.study.serv…...
自然语言处理从入门到应用——LangChain:记忆(Memory)-[聊天消息记录]
分类目录:《自然语言处理从入门到应用》总目录 Cassandra聊天消息记录 Cassandra是一种分布式数据库,非常适合存储大量数据,是存储聊天消息历史的良好选择,因为它易于扩展,能够处理大量写入操作。 # List of contact…...
Python web实战之细说 Django 的单元测试
关键词: Python Web 开发、Django、单元测试、测试驱动开发、TDD、测试框架、持续集成、自动化测试 大家好,今天,我将带领大家进入 Python Web 开发的新世界,深入探讨 Django 的单元测试。通过本文的实战案例和详细讲解ÿ…...
pytorch 42 C#使用onnxruntime部署内置nms的yolov8模型
在进行目标检测部署时,通常需要自行编码实现对模型预测结果的解码及与预测结果的nms操作。所幸现在的各种部署框架对算子的支持更为灵活,可以在模型内实现预测结果的解码,但仍然需要自行编码实现对预测结果的nms操作。其实在onnx opset===11版本以后,其已支持将nms操作嵌入…...
【Lua】(一)VSCode 搭建 Lua 开发环境
前言 最近在找工作,基本所有的岗位都会问到 Lua(甚至拼 UI 的都要求会 Lua),咱能怎么办呢,咱也只能学啊…… 工欲善其事,必先利其器。第一步,先来把环境配置好吧! 当前适用版本&a…...
react-vite-antd环境下新建项目
vite 创建一个react项目 1. 安装vite并创建一个react项目1. 我使用的 yarn安装,基本配置项目名字, 框架react ,js2. cd vite-react进入项目目录安装node包并启动项目 2. 安装引入Ant Design引入依赖(我用的yarn,没有安装的也可以使…...
KeilMDk软仿真设置_STM32F03C8
1、KeilMDK软仿真的价值 (1)在没有硬件的情况下进行程序的编写调试。 (2)避免频繁的下载程序,延长单片机Flash寿命。 2、软仿真配置。 (1)打开Keil工程。 (2)点击“Options for Target ***”,如下图所示。 (3)点击“Debug”。 (4)进行如下配置。 U…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...
pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...
OpenGL-什么是软OpenGL/软渲染/软光栅?
软OpenGL(Software OpenGL)或者软渲染指完全通过CPU模拟实现的OpenGL渲染方式(包括几何处理、光栅化、着色等),不依赖GPU硬件加速。这种模式通常性能较低,但兼容性极强,常用于不支持硬件加速…...
