linux_回收子进程(何为孤儿进程、僵尸进程、wait函数、waitpid函数)

news2025/1/18 11:50:26

接上一篇:linux_exec函数族-execl函数-execlp函数-execle函数-execv函数-execvp函数-execve函数

今天来向大家分享几个有趣的知识点,一个是孤儿进程,一个是僵尸进程,hhh,是不是很有趣,另外再来看看怎么去回收子进程,开始上菜:

目录

  • 1.孤儿进程
  • 2.僵尸进程
  • 3.wait函数
    • 例子-回收正常进程:
    • 例子-回收异常进程:
  • 4.waitpid函数
    • 例子-阻塞回收一个进程:
    • 例子-阻塞等待回收所有子进程:
    • 例子-非阻塞等待回收子进程:

1.孤儿进程

  孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,此时子进程的父进程就成为init进程,该子进程就相当于被init进程领养。
  init进程是linux内核启动的第一个进程。

2.僵尸进程

  僵尸进程: 进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。
红框中:
  S:在后台运行
  R:正在运行
  Z:僵尸进程,已死亡状态
  defunct:该进程死亡了
在这里插入图片描述

3.wait函数

  一个进程在结束时,是需要父进程进行回收的,此时可以调用wait函数来进行回收。
当进程终止时,操作系统的隐式回收机制会:
  1.关闭所有文件描述符;
  2. 释放用户空间分配的内存。内核的PCB仍存在。其中保存该进程的退出状态。(正常终止→退出值;异常终止→终止信号)
函数作用:
  ① 阻塞等待子进程退出
  ② 回收子进程残留资源
  ③ 获取子进程结束状态(退出原因)。
头文件:
  #include <sys/types.h>
  #include <sys/wait.h>
函数原型:
  pid_t wait(int *status);
函数参数:
  status:用来保存进程退出的状态
可使用wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的具体原因。宏函数可分为如下三组:

1.  WIFEXITED(status) 为非0	→ 进程正常结束
	WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)
2. 	WIFSIGNALED(status) 为非0 → 进程异常终止
	WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。
3. 	WIFSTOPPED(status) 为非0 → 进程处于暂停状态
	WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。
	WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行

  一次wait调用,只回收一个子进程,阻塞状态回收子进程,也就是调用该函数,会停在这里等待回收子进程。

返回值:
  成功返回被终止子进程的进程ID;
  错误返回-1。

例子-回收正常进程:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
	pid_t pid, wpid;
	pid = fork();
	if(pid == -1)
	{
		perror("fork error");
		exit(1);
	} 
	else if(pid == 0)
	{		//子进程
		printf("子进程ID = %d\n", getpid());
		sleep(5);				
	} 
	else 
	{
		wpid = wait(NULL);	//阻塞等待回收子进程	
		if(wpid == -1)
		{
			perror("wait error");
		}
		printf("父进程回收的子进程ID = %d\n", wpid);
	}
	return 0;
}

例子-回收异常进程:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
	pid_t pid, wpid;
	int status;

	pid = fork();

	if(pid == -1)
	{
		perror("fork error");
		exit(1);
	} 
	else if(pid == 0)
	{		//son
		printf("我是子进程, pid = %d\n", getpid());
#if 0
		//错误退出测试
		execl("./xxx", "abnor", NULL);
		perror("execl error");
		exit(1);
#endif
		sleep(1);				
		exit(10);
	} 
	else 
	{
		//wpid = wait(NULL);	//传出参数
		wpid = wait(&status);	//传出参数

		if(WIFEXITED(status))
		{	//正常退出
			printf("我是父进程,子进程 %d 正常退出!\n", wpid);
			printf("返回值: %d\n", WEXITSTATUS(status));

		} 
		else if (WIFSIGNALED(status)) 
		{	
			//异常退出
			printf("子进程 %d 异常退出!返回值为:%d\n", wpid, WTERMSIG(status));	//获取信号编号
		} 
		else 
		{
			printf("other...\n");
		}
	}
	return 0;
}

4.waitpid函数

函数作用:
作用同wait,但可指定pid进程清理,可以不阻塞。
头文件:
  #include <sys/types.h>
  #include <sys/wait.h>
函数原型:
  pid_t waitpid(pid_t pid, int *status, in options);
函数参数:

参数pid: 
	> 0  回收指定ID的子进程,回收指定子进程时,只要该子进程结束,就可回收,回收时间>=子进程结束时间。
	-1   回收任意子进程(相当于wait)
	0    回收和当前调用waitpid一个组的所有子进程
	<-1 回收指定进程组内的任意子进程    可以和kill命令一起使用,例如:kill -9 -进程组ID
参数options:
	0 :表示阻塞状态回收子进程
	WNOHANG:表示非阻塞状态回收子进程

返回值:
  成功:返回清理掉的子进程ID;
  失败:-1(无子进程)
特殊返回值:
  当返回0:参数3为WNOHANG,表示子进程正在运行。

注意:
一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。
ps ajx #可以查看进程组ID

例子-阻塞回收一个进程:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
	int n = 3, i;				
    pid_t p, q = -1;
	//默认创建3个子进程
	for(i = 0; i < n; i++)	 
    {
        //创建子进程
        p = fork();
		if (i == 1)
        {
            //获得子进程为2的进程id
            q = p;
        }
		if(p == 0) 
        {
			break;			//出口2,子进程出口,i不自增
        }
    }
	if(n == i)
    {
		sleep(n);
		waitpid(q, NULL, 0);//阻塞状态回收q子进程,也就是第2个子进程,其他子进程不回收
		printf("我是父进程, pid = %d,子进程 %d 已被回收!\n", getpid(),q);
        while(1);
	} 
    else {
		sleep(i);
		printf("我是第 %d 个子进程, pid = %d, 组pid=%d\n", 
				i+1, getpid(), getgid());
		if(i != 1)
		{
			//while(1);
		}
	}
	return 0;
}

例子-阻塞等待回收所有子进程:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
	int n = 5, i;				
    pid_t p, q;
    //默认创建5个子进程
	for(i = 0; i < n; i++)	 
    {
        p = fork();
		if (i == 3)
        {
            q = p;
        }
		if(p == 0) {
			break;			//子进程出口,i不自增
        }
    }
	if(n == i){
		sleep(n);
		while(waitpid(-1, NULL, 0) != -1);//阻塞状态回收全部子进程
		printf("已回收所有的子进程!\n");
	} 
    else 
    {
		sleep(i);
		printf("我是第%d个子进程, pid = %d, 组pid=%d\n", i+1, getpid(), getgid());
	}
	return 0;
}

例子-非阻塞等待回收子进程:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

int main(void)
{
	pid_t pid, pid2,wpid;
	int flg = 0;
	int k = 0;
	for (size_t i = 0; i < 2; i++)
	{
		pid = fork();//创建一个子进程
		k = i;
		if(pid == 0)
		{
			break;
		}
	}
	if(pid == -1)
    {
        //创建失败
		perror("fork error");
		exit(1);
	} 
    else if(pid == 0)
    {		
        //子进程
		printf("我是子进程, pid = %d\n", getpid());
		if(k == 0)
		{
			sleep(3);
		}
		else
		{
			sleep(8);
		}
		exit(2);//结束
	}
	else {					//父进程
		//等待回收子进程,会等待所有的子进程回收完才退出程序
		do {
			wpid = waitpid(-1, NULL, WNOHANG);//获取进程状态,wpid>0,表示回收了一个进程
			
			printf("---wpid = %d--------%d\n", wpid, flg++);//打印log
			if(wpid == 0)
            {
                //返回0表示有子进程正在运行,没有结束
				printf("NO child exited\n");
				sleep(1);		
			}
			else
            {
				k--;
			}
		} while (k >= 0);		//子进程不可回收
		//进程全部回收完毕
		printf("我是父进程,pid = %d,所有子进程回收完毕!\n", wpid);
	}

	return 0;
}

以上就是本次的分享了,希望能对广大网友有所帮助。

此博主在CSDN发布的文章目录:【我的CSDN目录,作为博主在CSDN上发布的文章类型导读】

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

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

相关文章

Kubernetes集群调度增强之超容量扩容

作者&#xff1a;京东科技 徐宪章 1 什么是超容量扩容 超容量扩容功能&#xff0c;是指预先调度一定数量的工作节点&#xff0c;当业务高峰期或者集群整体负载较高时&#xff0c;可以使应用不必等待集群工作节点扩容&#xff0c;从而迅速完成应用横向扩容。通常情况下HPA、Cl…

链表与邻接表|栈与队列|kmp

目录 单链表&#xff08;邻接表&#xff09; 双链表 数组模拟栈、队列 单调栈 单调队列&#xff08;滑动窗口&#xff09; KMP 一、KMP算法基本概念与核心思想 二、next数组的含义 三、匹配的思路 四、求next数组 单链表&#xff08;邻接表&#xff09; #include &…

Linux操作基础(系统安全及应用)

文章目录一 、账号安全基本措施1.1 系统账号清理1.2 密码安全控制1.21 设置密码有效期1.3 命令历史限制1.31 修改history命令条数1.32 清空history的方式1.33 设置终端自动注销二 、使用su命令切换用户2.1 限制使用su命令切换用户2.2 sudo命令—提升执行权限三 、系统引导和登录…

OpenCV:介绍 SURF(加速稳健特征)以及其使用

我们将了解 SURF 的基础知识 我们将了解 OpenCV 中的 SURF 功能 理论 在上一章中,我们学习了 SIFT 用于关键点检测和描述的方法。但它相对较慢,人们需要更快速的版本。2006年,Bay, H., Tuytelaars, T. 和 Van Gool, L 发表了另一篇论文 "SURF: 加速稳健特征",介…

机器学习:多项式拟合分析中国温度变化与温室气体排放量的时序数据

文章目录1、前言2、定义及公式3、案例代码1、数据解析2、绘制散点图3、多项式回归、拟合4、注意事项1、前言 ​ 当分析数据时&#xff0c;如果我们找的不是直线或者超平面&#xff0c;而是一条曲线&#xff0c;那么就可以用多项式回归来分析和预测。 2、定义及公式 ​ 多项式…

《花雕学AI》哪种技能5年10年后还会被市场需要? 该如何提高这些能力?

随着AI人工智能、ChatGPT等新的技术革新的发展&#xff0c;未来职业场景确实会发生变化&#xff0c;一些传统的职业可能会被取代&#xff0c;而一些新的职业可能会出现。根据世界经济论坛所发布的《未来就业报告》&#xff0c;一半的劳动力需要在2025年之前完成技能重塑。那么&…

Harmony OS 开发指南——DevEco Device Tool 安装配置

本文介绍如何在Windows主机上安装DevEco Device Tool工具。 坑点总结&#xff1a; 国内部分网络环境下&#xff0c;安装npm包可能会很慢或者超时&#xff0c;推荐使用国内npm源&#xff08;如淘宝源、华为源等&#xff09;&#xff1b;serialport这个npm包安装的过程中需要编…

C/C++笔记-记录一次对qmake生成的Makefile的分析(2023-02-07)

如下Qt代码&#xff1a; ConsoleDemo.pro QT core QT - guiTARGET ConsoleDemo CONFIG console CONFIG - app_bundleTEMPLATE appSOURCES main.cpp main.cpp #include <QCoreApplication> #include <QDebug>int main(int argc, char *argv[]) {QCoreApplic…

安装Kafka 基础命令

目录 解压 改名 修改配置文件 创建目录用于存放日志 创建修改myid 添加环境变量 刷新环境变量 测试 启动zookeeper 启动kafka 关闭kafka kafka基础命令 查看消息队列 创建消息队列 查看队列详情 查询指定队列消息数量 生产者消费者 生产消息 消费消息 解压 …

简单分享婚庆小程序开发怎么做

婚庆行业的服务范围不再仅限于婚纱照、婚礼主持等服务&#xff0c;消费者希望在婚庆服务商获得更多的服务&#xff0c;导致行业服务范围不断扩大、服务类目越发丰富&#xff0c;而商家在此基础上&#xff0c;更需要考虑提高服务质量与效率&#xff0c;合理利用资源提供服务。小…

Jmeter5.1的安装

1.由于&#xff0c;jmeter 是用纯java开发的一个可跨平台的绿色软件&#xff0c;所以&#xff0c;我们在使用jmeter之前&#xff0c;必须要安装基于Windows下的jdk环境。下面安装jdk,检查是否安装jdk方法&#xff08;cmd运行输入java -version&#xff09;&#xff0c;如下图显…

81.qt qml-Canvas深入学习之好看的水纹波自定义控件V2

界面如下所示(外观参考ECharts 源码通过QML控件实现): 效果如下所示: 支持自定义颜色、自定义波峰数量、增幅、速度、水平偏移等 1.介绍 在我们之前38章38.qt quick-QML水纹波进度条_诺谦的博客-CSDN博客 写过一个简单的水纹波: 所以本质差不多. 2.QianRippleChartPage代码 该…

webgl-矩阵、旋转、平移、缩放

关键代码 旋转 /* * [ * cosB, -sinB, 0, 0, * sinB, cosB, 0, 0, * 0, 0, 1, 0, * 0, 0, 0, 1 * ] * * 矩阵本该是这个但是由于webgl的矩阵行和列是颠倒的所以我们传入的矩阵也需要倒置 */ rotationMatrix [ cosB, sinB, 0, 0, -sinB, cos…

[Python工匠]输出③容器类型

在Python中&#xff0c;最常见的内置容器类型有四种&#xff1a;列表、元组、字典、集合。 列表&#xff08;list&#xff09;是一种非常经典的容器类型&#xff0c;通常用来存放多个同类对象&#xff0c;比如从1到10的所有整数&#xff1a; 元组&#xff08;tuple&#xff09;…

phpstudy本地环境搭建图文教程

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。我的…

chatgpt VS 文心一言使用对比实测

chatgpt VS 文心一言使用对比实测 什么是文心一言 文心一言&#xff08;英语&#xff1a;ERNIE Bot&#xff09;是由百度公司开发的聊天机器人&#xff0c;能够与人交互、回答问题及协作创作。该产品被传媒称为国际著名聊天机器人ChatGPT的中国版及其竞争对手[1][2]。目前已开…

机器学习——数据处理

机器学习简介 机器学习是人工智能的一个实现途径深度学习是机器学习的一个方法发展而来 机器学习&#xff1a;从数据中自动分析获得模型&#xff0c;并利用模型对未知数据进行预测。 数据集的格式&#xff1a; 特征值目标值 比如上图中房子的各种属性是特征值&#xff0c;然…

数据结构——哈希表相关题目

数据结构——哈希表相关题目242. 有效的字母异位词1.暴力解法2.排序后比较3.哈希表383. 赎金信哈希解法49. 字母异位词分组438. 找到字符串中所有字母异位词3. 无重复字符的最长子串76. 最小覆盖子串349. 两个数组的交集1.排序双指针2.哈希表350. 两个数组的交集 II1.排序双指针…

C++缺省参数详解

在C中&#xff0c;我们经常需要定义函数并给它们传递一些参数。有时候&#xff0c;某些参数的值是不经常改变或者只有特殊情况下才需要指定&#xff0c;这时候我们可以用缺省参数来简化代码。 什么是缺省参数&#xff1f; 缺省参数是声明或定义函数时为函数的参数指定一个缺省…

javascript 中使用 ActiveMQ

javascript 中使用 ActiveMQ 1. 参考文档 https://www.eclipse.org/paho/files/jsdoc/index.html 2. html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" con…