Linux中sigaction函数和SIGCHLD信号的使用
sigaction函数:
函数说明:注册一个信号处理函数
函数原型:int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
函数参数:
- signum:捕捉的信号
- act:传入参数,新的处理方式
- oldact:传出参数,旧的处理方式
The sigaction structure is defined as something like:struct sigaction {void (*sa_handler)(int);//信号处理函数void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;//信号处理函数执行期间需要阻塞的信号,信号处理函数结束后,就不阻塞了int sa_flags;//通常为0,表示默认标识void (*sa_restorer)(void);};
测试:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include <signal.h>
#include <sys/time.h>
void handler(int signo)
{printf("signo==[%d]\n",signo);sleep(5);
}
int main()
{//int sigaction(int signum, const struct sigaction *act,// struct sigaction *oldact);struct sigaction act;act.sa_handler=handler;sigemptyset(&act.sa_mask);把set信号集全部置0,不阻塞任何信号act.sa_flags=0;sigaction(SIGINT,&act,NULL);while(1){sleep(1);}return 0;
}
结果:

由结果我们可以知道在XXX信号处理函数执行期间,当XXX信号产生多次,该信号进入未决信号集中(被阻塞),在信号处理函数执行结束后,只会执行一次(信号不支持排队)。
若在sa_mask中阻塞了YYY信号,那么在XXX信号处理函数执行时,产生的YYY信号也会进入未决信号集中(被阻塞),等到XXX信号处理函数结束后执行一次。
SIGCHLD信号:
产生SIGCHLD信号的条件:
- 子进程结束的时候
- 子进程收到SIGSTOP信号
- 当子进程停止时,收到SIGCONT信号
SIGCHLLD信号的作用:
子进程退出后,内核会给它的父进程发送SIGCHLD信号,父进程收到这个信号后可以使用wait/waitpid函数对子进程进行回收。
父进程创建两个子进程,然后让父进程捕获SIGCHLD信号完成对子进程的回收
注意点:
有可能还未完成注册信号处理函数,两个子进程已经都退出了
解决方法:可以在fork之前先将SIGCHLD阻塞,当完成信号处理函数的注册后解除阻塞
当SIGCHLD信号函数处理期间,SIGCHLD信号若再次产生是被阻塞的,而且产生多次,最后只会被处理一次,这样就会产生僵尸进程
解决方法:可以在信号处理函数里面使用while(1)循环回收,这样就有可能出现捕获一次SIGCHLD信号但是回收了多个子进程的情况,从而避免产生僵尸进程
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<signal.h>
void handler(int signo)//信号处理函数
{//pid_t waitpid(pid_t pid, int *wstatus, int options);pid_t wpid;while(1)//一直死循环,防止信号处理函数执行的时候,有多个子进程终止(只会接收一次SIGCHLD信号),产生僵尸进程{wpid=waitpid(-1,NULL,WNOHANG);//设为非阻塞,因为子进程收到SIGSTOP,SIGCONT信号,也会发出SIGCHLD信号,这样一来并没有子进程终止,就会一直阻塞if(wpid>0){printf("[%d]child is quit\n",wpid);}else if(wpid==0)//还有子进程运行,break,等下一个SIGCHLD信号{break;}else if(wpid==-1)//没有子进程,已经全部回收,break{printf("no child is living\n");break;}}
}
int main()
{
//先把SIGCHLD信号阻塞,防止还没有注册信号处理函数时,就已经有SIGCHLD信号产生,被忽略sigset_t set;sigemptyset(&set);sigaddset(&set,SIGCHLD);
// int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);sigprocmask(SIG_BLOCK,&set,NULL);int i=0;for(;i<2;i++)//循环产生两个兄弟子进程{pid_t pid=fork();if(pid<0){perror("fork error");return -1;}else if(pid>0){printf("father:pid=[%d]\n",getpid());}else if(pid==0){break;}}if(i==0){printf("[%d]child:pid=[%d],fpid=[%d]\n",i,getpid(),getppid());}else if(i==1){printf("[%d]child:pid=[%d],fpid=[%d]\n",i,getpid(),getppid());}else if(i==2){struct sigaction act;act.sa_handler=handler;sigemptyset(&act.sa_mask);act.sa_flags=0;sigaction(SIGCHLD,&act,NULL);//注册信号处理函数sigprocmask(SIG_UNBLOCK,&set,NULL);//把SIGCHLD信号设置为非阻塞while(1){sleep(1);}}return 0;
}
结果:
使用信号传递让父子进程来回计数
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>
//定义成全局变量,不然回调函数无法辨认
int num=0;//从0开始计数
int flag=0;//开关变量
void func1(int signo)//父进程的信号处理函数
{printf("f:[%d]\n",num);num+=2;flag=0;sleep(1);
}
void func2(int signo)//子进程的信号处理函数
{printf("c:[%d]\n",num);num+=2;flag=0;sleep(1);
}
int main()
{pid_t pid=fork();if(pid<0){perror("fork error");return -1;}else if(pid>0){signal(SIGUSR1,func1);//注册信号处理函数flag=1;//开关初始为1,让子进程先发出SIGUSR2信号给父进程while(1){if(flag==0){kill(pid,SIGUSR2);flag=1;}}}else if(pid==0){num=1;//子进程从一开始计数signal(SIGUSR2,func2);while(1){if(flag==0){kill(getppid(),SIGUSR1);flag=1;}}}
}
结果:

相关文章:
Linux中sigaction函数和SIGCHLD信号的使用
sigaction函数: 函数说明:注册一个信号处理函数 函数原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 函数参数: signum:捕捉的信号act:传入参数,…...
【MySQL】操作库 —— 表的操作 -- 详解
一、增加表 1、创建表 mysql> create database [if not exists] table_name ( -> field1 datatype, -> field2 datatype, -> field3 datatype -> ) character set 字符集 collate 校验规则 engine 存储引擎; 注意 :最后一行也可以写成&#x…...
ZigBee学习——在官方例程实现组网
✨Z-Stack版本:3.0.2 ✨IAR版本:10.10.1 ✨这篇博客是在善学坊BDB组网实验的基础上进行完善,并指出实现的过程中会出现的各种各样的问题! 善学坊教程地址: ZigBee3.0 BDB组网实验 文章目录 一、基础工程选择二、可能遇…...
ES实战--wildcard正则匹配exists过滤字段是否存在
wildcard 通配符中的 * 表示任意数量的字符 ?表示任意单个字符 #正则匹配 GET /wildcard-test/_search {"query": {"wildcard": {"title": {"wildcard": "ba*n"}}} } #响应:"hits": {"total": {"…...
C++学习:二分查找
二分查找的前提 库函数只能对数组进行二分查找。 对一个数组进行二分查找的前提是这个数组中的元素是单调的。 一般为单调不减,当然如果是单调不增也可以(需要修改比较函数) 例如: [1,5,5,9,18]是单调的 [1 , 9, 9,…...
语言与科技创新(大语言模型对科技创新的影响)
1.语言因素对科技创新的影响 科技创新中的语言因素至关重要,具体体现在以下几个方面: 科技文献交流: 英语作为全球科学研究的通用语言,极大地推动了科技成果的国际传播与合作。在国际上,科学家们在发表论文、报告研究…...
【C语言】简单贪吃蛇实现保姆级教学!!!
关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა 新年快乐呀小伙伴 引言: 小伙伴们应该都有一个做游戏的梦吧?今天让小庄来用C语言简单实现一下我们的童年邪典贪吃蛇,顺便巩固我们的C语言知识,请安心食用~ 文章目录 贪吃蛇效果一.游戏前工作…...
rtt设备io框架面向对象学习-uart设备
目录 1.uart设备基类2.uart设备基类的子类3.初始化/构造流程3.1设备驱动层3.2 设备驱动框架层3.3 设备io管理层 4.总结5.使用 1.uart设备基类 此层处于设备驱动框架层。也是抽象类。 在/ components / drivers / include / drivers 下的serial.h定义了如下uart设备基类 struc…...
Innodb下修改事务工作流程(buffer pool、redo log、undolog)
1、在Buffer Pool中读取数据:当InnoDB需要更新一条记录时,首先会在Buffer Pool中查找该记录是否在内存中。如果没有在内存中,则从磁盘读取该页到Buffer Pool中。 2、记录UndoLog:在修改操作前,InnoDB会在Undo Log中记…...
redis为什么使用跳跃表而不是树
Redis中支持五种数据类型中有序集合Sorted Set的底层数据结构使用的跳跃表,为何不使用其他的如平衡二叉树、b树等数据结构呢? 1,redis的设计目标、性能需求: redis是高性能的非关系型(NoSQL)内存键值数据…...
【matalab】基于Octave的信号处理与滤波分析案例
一、基于Octave的信号处理与滤波分析案例 GNU Octave是一款开源软件,类似于MATLAB,广泛用于数值计算和信号处理。 一个简单的信号处理与滤波分析案例,说明如何在Octave中生成一个有噪声的信号,并设计一个滤波器来去除噪声。 首…...
Elasticsearch:特定领域的生成式 AI - 预训练、微调和 RAG
作者:来自 Elastic Steve Dodson 有多种策略可以将特定领域的知识添加到大型语言模型 (LLM) 中,并且作为积极研究领域的一部分,正在研究更多方法。 对特定领域数据集进行预训练和微调等方法使 LLMs 能够推理并生成特定领域语言。 然而&#…...
HarmonyOS—UI 开发性能提升的推荐方法
开发者若使用低性能的代码实现功能场景可能不会影响应用的正常运行,但却会对应用的性能造成负面影响。本章节列举出了一些可提升性能的场景供开发者参考,以避免应用实现上带来的性能劣化。 使用数据懒加载 开发者在使用长列表时,如果直接采用…...
84 CTF夺旗-PHP弱类型异或取反序列化RCE
目录 案例1:PHP-相关总结知识点-后期复现案例2:PHP-弱类型对比绕过测试-常考点案例3:PHP-正则preg_match绕过-常考点案例4:PHP-命令执行RCE变异绕过-常考点案例5:PHP-反序列化考题分析构造复现-常考点涉及资源…...
Duilib List 控件学习
这是自带的一个示例; 一开始运行的时候List中是空的,点击Search按钮以后就填充列表框; 先看一下列表框列头是在xml文件中形成的; <List name="domainlist" bkcolor="#FFFFFFFF" ... menu="true"> <ListHeader height="24…...
详细了解Node.js的配置与使用!
详细了解Node.js的配置与使用! Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。它允许开发者在服务器端运行 JavaScript,从而实现全栈 JavaScript 开发。本文将介绍 Node.js 的配置和 npm 的应用。 一、Node.js 配置 下载与安装 首先&…...
OpenCV 移动最小二乘图像变形
文章目录 一、简介二、实现代码三、实现效果参考文献一、简介 在现实生活中,我们常常应用一些刚性的变换来实现物体的旋转平移,对于非刚性的变换我们都没有在意,其实这种变换也是无处不在的,如我们经常看的动画就可以通过一些非刚性的变换达到一些非常夸张的效果。这里,我…...
【深度学习】S2 数学基础 P4 概率论
目录 基本概率论概率论公理随机变量 多个随机变量联合概率条件概率贝叶斯定理求和法则独立性 期望与方差小结 基本概率论 机器学习本质上,就是做出预测。而概率论提供了一种量化和表达不确定性水平的方法,可以帮助我们量化对某个结果的确定性程度。 在…...
跟我学c++中级篇——静态多态
一、多态 Polymorphism,多态。学习过c的人如果不知道多态,基本上就是打入c内部的C程序员了。在前边曾经对多态进行过分析,对其中的虚函数(虚表等)也进行过较为详细的说明。 多态其实非常好理解,不要硬扣书…...
设计模式--桥接模式(Bridge Pattern)
桥接模式(Bridge Pattern)是一种结构型设计模式,它主要是用于将抽象部分与实现部分分离,使它们可以独立地变化。 桥接模式主要包含以下几个角色: Abstraction(抽象类):定义抽象类的…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
