【Linux】SIGCHLD信号

文章目录

  • SIGCHLD信号

SIGCHLD信号

回忆:

为了避免出现僵尸进程,父进程需要使用wait或waitpid函数等待子进程结束,父进程可以阻塞等待子进程结束,也可以非阻塞地查询的是否有子进程结束等待清理,即轮询的方式

  • 如果采用阻塞等待:父进程阻塞就不能处理自己的工作了
  • 如果采用非阻塞等待:父进程在处理自己的工作的同时还要记得时不时地轮询一下,程序实现复杂

引入

子进程在终止时会给父进程发生SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理动作,这样父进程就只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait或waitpid函数清理子进程即可


例子:

这里写一个监视脚本:

while :; do ps axj | head -1 && ps axj | grep signal | grep -v grep; sleep 1; echo "################"; done

下述中对SIGCHLD信号进行了捕捉,并将在该信号的处理函数中调用了waitpid函数对子进程进行了清理,如果不清理,子进程还是僵尸进程

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
void GetChild(int signo)
{
	waitpid(-1,NULL,WNOHANG);
	printf("get a signal:%d,pid:%d\n",signo,getpid());
}
int main()
{
	signal(SIGCHLD,GetChild);//捕捉SIGCHLD信号, 也可以写成:singal(17,GetChild)
	pid_t id = fork();
	if(id == 0)
	{
		//child
		int count = 5;
		while(count)
		{
			printf("我是子进程:%d\n",getpid());
			sleep(1);
			count--;
		}
		exit(0);
	}
	//father
	//子进程一旦退出,父进程在while循环期间也一定能够收到SIGCHLD信号
	//因为对SIGCHLD信号进行捕捉,所以执行自定义逻辑
	while(1) ;
	return 0;
}

image-20220817130653715


但是实际上:父进程在信号处理函数这样写会比较好:

void handle(int signo)
{
    printf("get a signal: %d\n", signo);
    int ret = 0;
    while ((ret = waitpid(-1, NULL, WNOHANG)) > 0) //WNOHANG:非阻塞等待
    {
        printf("wait child %d success\n", ret);
    }
}

含义:

  1. SIGCHLD属于普通信号,记录该信号的pending位只有一个,如果在同一时刻有多个子进程同时退出,那么在handler函数当中实际上只清理了一个子进程,因此在使用waitpid函数清理子进程时需要使用while不断进行清理

2)使用waitpid函数时,需要设置 WNOHANG 选项,即非阻塞式等待,否则当所有子进程都已经清理完毕时,由于while循环,会再次调用waitpid函数,此时就会在这里阻塞住

问题1:为什么要用循环等待

这样的写法能够满足各种子进程退出的情况,假设创建10个子进程, 它们同时退出了,每个子进程退出都向父进程发送信号, 但是pending位图只能有一个比特位记录这个SIGCHILD信号, 如果只wait一次,那么只能读取一个子进程,剩下的9个就没被读到,所以设置while循环, 不等待指定一个子进程->所以参数设定-1循环式的把所有子进程退出都读取到

问题2:为什么要非阻塞等待呢?

假设5个进程退出,5个没退出, 前五个退出的进程全读完了,还要读第6次, 我们刚才是站在上帝视角,实际我们不知道有多少个进程退出了, 当读取一个子进程退出,那就继续读,只有读取失败的时候才知道没有子进程退出了

如果用阻塞,上述情况下,当我们读取第6次的时候, 如果子进程不退出就在信号捕捉这里卡住了,所以使用非阻塞等待可以防止程序卡住的情况


下面代码中对SIGCHLD信号进行了捕捉,并将在该信号的处理函数中调用了waitpid函数对子进程进行了清理

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/wait.h>
void handler(int signo)
{
	printf("get a signal: %d\n", signo);
	int ret = 0;
	while ((ret = waitpid(-1, NULL, WNOHANG)) > 0)
	{
		printf("wait child %d success\n", ret);
	}
}

int main()
{
	signal(SIGCHLD, handler);//捕获SIGCHLD信号
	if (fork() == 0)
	{
		//child
		printf("child is running, pid: %d\n", getpid());
		sleep(3);
		exit(1);
	}
	//father
	while (1);
	return 0;
}

image-20220817135044146


要想不产生僵尸进程还有另外一种办法:父进程调用signal或sigaction函数将SIGCHLD信号的处理动作设置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程.系统默认的忽略动作和用户用signal或sigaction函数自定义的忽略通常是没有区别的,但这是一个特列.此方法对于Linux可用,但不保证在其他UNIX系统上都可用

例子:调用signal函数将SIGCHLD信号的处理动作自定义为忽略

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
int main()
{
    signal(SIGCHLD, SIG_IGN);//将SIGCHLD信号的处理动作自定义为忽略
    if (fork() == 0)
    {
        //child
        printf("child is running, child pid: %d\n", getpid());
        sleep(3);
        exit(1);
    }
    //father
    while (1);
    return 0;
}

此时我们发现:进程在终止时会自动被清理掉,不会产生僵尸进程,也不会通知父进程

image-20220817135331404

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python日志logging实战教程

一、什么是日志 在《网络安全之认识日志采集分析审计系统》中我们认识了日志。日志数据的核心就是日志消息或日志&#xff0c;日志消息是计算机系统、设备、软件等在某种刺激下反应生成的东西。 日志数据&#xff08;log data&#xff09;就是一条日志消息的内在含义&#xf…

第十四届蓝桥杯第三期模拟赛 【python】

第十四届蓝桥杯第三期模拟赛 【python】 文章目录第十四届蓝桥杯第三期模拟赛 【python】✨最小的十六进制&#xff08;python的16进制&#xff09;❓️问题描述答案提交&#x1f9e0;思路&#x1f5a5;︎参考答案✨Excel的列&#xff08;进制转化&#xff09;❓️问题描述答案…

串口通信(STM32演示实现)

目录 一、串行通信的概念 二、寄存器 2.1控制寄存器USART_CR1 2.2控制寄存器USART_CR2​编辑 2.3串口寄存器USART_BRR 2.4 USART_ISR 2.5USART_TDR 2.6USART_RDR​编辑 三、实现串口数据的收发 一、串行通信的概念 u通信&#xff0c;最少要有两个对象&#xff0c;一个收…

强化学习、监督学习、无监督学习是什么

1 强化学习 1.1 定义 强化学习是机器学习学习方式的一种&#xff0c;是让计算机实现从一开始完全随机的进行操作&#xff0c;通过不断试错的方式去总结出每一步的最佳行为决策&#xff0c;基于环境给予的反馈&#xff0c;去调整自己的行为决策&#xff0c;从而对未来的行为给…

什么是推挽输出,开漏输出?

这篇文章是看B站“工科男孙老师”这个视频的笔记推挽 开漏 高阻 这都是谁想出来的词&#xff1f;&#xff1f; 我觉得讲的很好&#xff0c;做一下笔记 1.什么是IO输出三态 一共有&#xff1a;高电平, 低电平&#xff0c;浮空/高阻态 三种IO态 2.推挽输出 推挽输出能够表示高、…

短链接是怎么设计的?带你入门

文章目录前言一、短链1、原理1.1 短链生成原理1.2 短链跳转原理&#xff1a;2、设计&#xff1a;2.1 短链需求2.2 考虑的问题&#xff1f;二、实践案例1、设计表&#xff1a;2、生成短链&#xff1a;前言 说到 URL 你肯定不陌生&#xff0c;浏览器输入一段 URL&#xff0c;立马…

QMessageBox手动添加按钮并绑定按钮的信号

视频展示效果&#xff08;结合代码看效果更佳哦&#xff0c;代码在最下面&#xff09;&#xff1a; QMessageBox手动添加有重试效果的按钮效果图&#xff1a; 点击详细文本之后展开如下图&#xff1a; 图标可选&#xff1a; QMessageBox::Critical错误图标QMessageBox::NoIco…

第二十一天 数据库开发-MySQL

目录 数据库开发-MySQL 前言 1. MySQL概述 1.1 安装 1.2 数据模型 1.3 SQL介绍 1.4 项目开发流程 2. 数据库设计-DDL 2.1 数据库操作 2.2 图形化工具 2.3 表操作 3. 数据库操作-DML 3.1 增加(insert) 3.2 修改(update) 3.3 删除(delete) 数据库开发-MySQL 前言 …

深度学习:GPT1、GPT2、GPT-3

深度学习&#xff1a;GPT1、GPT2、GPT3的原理与模型代码解读GPT-1IntroductionFramework自监督学习微调ExperimentGPT-2IntroductionApproachConclusionGPT-3GPT-1 Introduction GPT-1&#xff08;Generative Pre-training Transformer-1&#xff09;是由OpenAI于2018年发布的…

从0到1深度学习环境搭建

目录第一步&#xff1a;安装anaconda第二步&#xff1a;创建一个虚拟环境试一下第三步&#xff1a;确定cuda算力&#xff0c;配置cudapytorch官网找版本pycharm配置pycharm进行设置setting 能够打开conda的shell终端如何给下载的项目设置合适的环境如果必须要低版本的pytorch才…

智驾芯片“性价比之王”凭何抢滩增量市场?

未来几年&#xff0c;智能驾驶功能将进入跨越式升级的阶段&#xff0c;同时L2将快速普及&#xff0c;L2进入集中放量的阶段。 包括自动泊车 (APA)、家庭区域记忆泊车 (HAVP)、交通拥堵辅助 (TJA)、高速辅助驾驶 (HWA)、自动辅助导航驾驶 (NOA) 等在内的功能已为普通车主耳熟能…

美颜sdk的动态面具、3D面具实现流程

在美颜sdk的实现中&#xff0c;面具是很重要的一个部分&#xff0c;不管是动态面具还是3D面具都需要实现的&#xff0c;我们在开发中常用的是动态面具和3D面具。但是两种面具有很多不同之处&#xff0c;比如制作材料、制作方式等等。在这里我们先来了解一下动态面具和3D面具是如…

8个不能错过的程序员必备网站,惊艳到我了!!!

程序员是一个需要不断学习的职业&#xff0c;不少朋友每天来逛CSDN、掘金等网站&#xff0c;但一直都抱着“收藏从未停止&#xff0c;学习从未开始”的态度&#xff0c;别骗自己了兄弟。在编程体系中&#xff0c;有很多不错的小工具&#xff0c;可以极大得提升我们的开发效率。…

电容在微分、积分电路中的本质以及应用

很多朋友觉得PID是遥不可及&#xff0c;很神秘&#xff0c;很高大上的一种控制&#xff0c;对其控制原理也很模糊&#xff0c;只知晓概念性的层面&#xff0c;知其然不知其所以然&#xff0c;那么本期从另类视角来探究微分、积分电路的本质&#xff0c;意在帮助理解PID的控制原…

第十四届蓝桥杯三月真题刷题训练——第 21 天

目录 第 1 题&#xff1a;灭鼠先锋 问题描述 运行限制 代码&#xff1a; 思路&#xff1a; 第 2 题&#xff1a;小蓝与钥匙 问题描述 答案提交 运行限制 代码&#xff1a; 思路 : 第 3 题&#xff1a;李白打酒加强版 第 4 题&#xff1a;机房 第 1 题&#xff1…

存储专题扩容,HA、LB分布式存储

一、架构与存储的关系一个新的硬盘在linux系统里使用一般来说就三步:(分区,格式化)-挂载-使用blocklvs:四层负载均衡&#xff0c;nginx、haproxy四层和七层都有redis、memcache缓存中间件是缓存后端数据库读的信息。高端的容器技术&#xff0c;一旦系统出现可以可以直接重装系统…

【springboot】读写分离:

文章目录一、mysql主从复制&#xff08;从库可以有多个&#xff09;&#xff1a;【1】提前准备好两台服务器&#xff0c;分别安装Mysql并启动成功【2】配置---主库Master【3】配置---从库Slave【4】克隆的虚拟机导致mysql主从UUID一致怎么修改&#xff1a;【5】测试二、读写分离…

springboot学生综合测评系统

031-springboot学生综合测评系统演示录像2022开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&…

uniapp封装各个时间方法

难点&#xff1a;在项目中我们经常会用到时间转换或时间比对加减问题为了方便很多页面去调用时间方法&#xff0c;我把时间方法封装成了公共方法1.首先在根目录创建文件夹与pages平级&#xff0c;我这里创建了plugins文件夹2.其次在plugins文件夹下面创建index.js文件&#xff…

LeetCode题解 20(17,79) 电话号码的字母组合,单词搜索<回溯>

文章目录电话号码的字母组合(17)代码解答单词搜索(79)代码解答电话号码的字母组合(17) 思路: 根据题意我们必须根据数字获取对应的字符数组&#xff0c;因此我们先定义1个字符数组表示这个电话表 private String[] letters {"","","abc","…