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

父进程等待子进程退出 / 僵尸进程孤儿进程

Q:父进程为什么要等待子进程退出?

A:回顾创建子进程的目的,就是让子进程去处理一些事情,那么“事情干完了没有”这件事,父进程需要知道并收集子进程的退出状态子进程的退出状态如果不被收集,就会变成僵尸进程而如果父进程在子进程之前就退出了,则此时的子进程会变成孤儿进程。

而父进程会通过下面几个宏来解析具体返回的状态码:

 

僵尸进程

其实上上节的demo2的代码就会产生僵尸进程,因为父进程没有收集子进程的退出状态:

demo2.c:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main()
{pid_t pid;pid_t fork_return;int cnt = 0;pid = getpid();printf("before fork, PID = %d\n",pid);fork_return = vfork();if(fork_return > 0){while(1){printf("This is the father JC,PID = %d\n",getpid());sleep(2);}}else{while(1){printf("This is the son JC,PID = %d\n",getpid());sleep(2);cnt++;if(cnt == 3){exit(-1);}}}return 0;
}

运行效果:

看起来似乎运行效果很对,但如果使用"ps -aux|grep zombie"查看进程就会发现,PID号为3126的子进程已经变成了僵尸进程

“ S+ ”代表 进程正在正常运行中

“ Z+ ”代表 僵尸进程

孤儿进程 

Linux为了避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程。

修改demo2.c:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main()
{pid_t pid;pid_t fork_return;int cnt;pid = getpid();printf("before fork, PID = %d\n",pid);fork_return = fork();if(fork_return > 0){printf("This is the father JC,PID = %d\n",getpid());}else{while(1){printf("This is the son JC,PID = %d, my father JS's PID = %d\n",getpid(),getppid());sleep(2);cnt++;if(cnt == 3){exit(1);}}}return 0;
}

运行效果:

可见,父亲打印一条消息就会去世,在去世前,子进程的父亲就是原来程序的PID,但是当父亲离开后,子进程被PID为1797的进程收养了

通过“ps -aux” 查找1797:

但是根据概念,子进程不应该被PID号为1的进程收养吗?原因看这里:

父进程终止,子进程未被init收养问题_抱走♡的博客-CSDN博客 

所以是Linux的系统版本导致的问题应该= =

 

wait相关函数 

需要添加的库:

#include <sys/types.h>
#include <sys/wait.h>

wait函数原型:

 pid_t wait(int *wstatus);

参数说明1:

  • wstatus:这是一个整数型指针,如果设置为“NULL”,则表示不关心退出的状态如果不设置为“NULL”,则子进程退出的状态会放在这个指针指向的地址中

 

waitpid函数原型: 

waitpid和wait的区别就是,wait函数调用后在子进程退出前父进程会被强制阻塞而waitpid中有一个参数可以使得父进程不被阻塞。

pid_t waitpid(pid_t pid, int *wstatus, int options);

参数说明2:

  • pid:

  • wstatus:这是一个整数型指针,如果设置为“NULL”,则表示不关心退出的状态如果不设置为“NULL”,则子进程退出的状态会放在这个指针指向的地址中
  • options:

  1.  option如果设置为“WNOHANG”,则 若由PID指定的子进程不是立刻可用的,则waitpid不阻塞,此时其返回值为0
  2.  option如果设置为“WUNTRACED”,则 若某实现支持作业控制,而由PID指定的任一子进程已处于暂停状态,并且其状态自暂停以来还未报告过,则返回其状态,WIFSTOPPED宏确定返回值是否对应于一个暂停子进程
  3.  option如果设置为“WCONTINUED”,则 若实现支持作业控制,那么由PID指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态(POSIX.1的XSI拓展)

 

父进程等待退出并收集状态的演示

demo3.c:

使用wait函数,并将wstatus设置为NULL:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{pid_t pid;pid_t fork_return;int cnt = 0;pid = getpid();printf("before fork, PID = %d\n",pid);fork_return = fork();if(fork_return > 0){wait(NULL);while(1){printf("This is the father JC,PID = %d\n",getpid());sleep(2);}}else{while(1){printf("This is the son JC,PID = %d\n",getpid());sleep(2);cnt++;if(cnt == 3){exit(1);}}}return 0;
}

实现效果1:

 

可见虽然使用的是fork函数而不是vfork,但是由于父进程调用了wait函数,所以在子进程运行时一直阻塞,直到子进程退出,父进程才开始执行。

使用"ps -aux|grep demo3-1"查看进程:

可见,此时PID为3056的子进程已经完全退出,所以没有之前出现的僵尸进程了。 

使用wait函数,并不将wstatus设为NULL:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{pid_t pid;pid_t fork_return;int cnt = 0;int status = 0;pid = getpid();printf("before fork, PID = %d\n",pid);fork_return = fork();if(fork_return > 0){wait(&status);printf("child quit, exit status = %d\n",WIFEXITED(status));while(1){printf("This is the father JC,PID = %d\n",getpid());sleep(2);}}else{while(1){printf("This is the son JC,PID = %d\n",getpid());sleep(2);cnt++;if(cnt == 3){exit(1);}}}return 0;
}

注意,由于此时的子进程是正常退出则刚刚提到的宏“WIFEXITED”的值为真,并且可以使用 “WEXITSTATUS” 来解析状态,才可以得到正确的值

实现效果2:

可见,此时在子进程正常退出后,父进程在运行前还得到了子进程退出时的状态码

使用"ps -aux|grep demo3-2"查看进程:

可见,PID号为3109的子进程已经退出

 

demo4.c:

使用waitpid函数,并将option设为“WNOHANG”:

waitpid(fork_return,&status,WNOHANG);

回顾刚刚讲的PID参数如果>0,则等待“进程号等于这个PID”的子进程,而之前就说过fork的返回值就是子进程的PID,所以在这里直接将第一个参数设置为fork_return

实现效果:

可见,这次父进程没有阻塞并且直接返回,然后父子进程开始抢占CPU,等子进程成功执行三次退出之后,再次变成只有父进程在执行了。

 但是此时,使用"ps -aux|grep a.out"查看进程:

可见: PID号为3254的子进程变成了一个僵尸进程

所以,父进程的非阻塞等待会造成子进程变成僵尸进程!

 

 

相关文章:

父进程等待子进程退出 / 僵尸进程孤儿进程

Q&#xff1a;父进程为什么要等待子进程退出&#xff1f; A&#xff1a;回顾创建子进程的目的&#xff0c;就是让子进程去处理一些事情&#xff0c;那么“事情干完了没有”这件事&#xff0c;父进程需要知道并收集子进程的退出状态。子进程的退出状态如果不被收集&#xff0c;…...

【LeetCode 75】第二十六题(394)字符串解码

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 给我们字符串&#xff0c;让我们解码&#xff0c;那么该怎么解码呢&#xff0c;被括号【】包裹起来的字符串需要扩展成括号左边第…...

UNIX网络编程——TCP协议API 基础demo服务器代码

目录 一.TCP客户端API 1.创建套接字 2.connect连接服务器​编辑 3.send发送信息 4.recv接受信息 5.close 二.TCP服务器API 1.socket创建tcp套接字(监听套接字) 2.bind给服务器套接字绑定port,ip地址信息 3.listen监听并创建连接队列 4.accept提取客户端的连接 5.send,r…...

[保研/考研机试] KY163 素数判定 哈尔滨工业大学复试上机题 C++实现

题目链接&#xff1a; 素数判定https://www.nowcoder.com/share/jump/437195121691718831561 描述 给定一个数n&#xff0c;要求判断其是否为素数&#xff08;0,1&#xff0c;负数都是非素数&#xff09;。 输入描述&#xff1a; 测试数据有多组&#xff0c;每组输入一个数…...

iOS_crash文件的获取及符号化(解析)

文章目录 1. 使用 symbolicatecrash 解析 .ips 文件&#xff1a;2. 使用 CrashSymbolicator.py 解析 ips 文件3. 使用 atos 解析 crash 文件4. Helps4.1 .ips 文件获取4.2 .crash 文件获取4.3 获取 .dSYM 和 .app 文件4.4 使用 dwarfdump 查询 uuid 5. Tips6. 总结 1. 使用 sym…...

STM32定时器TIM控制

一、CubeMX的设置 1、新建工程&#xff0c;进行基本配置 2、配置定时器TIM2 1&#xff09;定时器计算公式&#xff1a;&#xff08;以下两条公式相同&#xff09; Tout ((ARR1) * PSC1)) / Tclk TimeOut ((Prescaler 1) * (Period 1)) / TimeClockFren Tout TimeOut&…...

网络请求中,token和cookie有什么区别

HTTP无状态&#xff0c;每次请求都要携带cookie&#xff0c;以帮助识别用户身份&#xff1b; 服务端也可以向客户端set-cookie&#xff0c;cookie大小限制为4kb&#xff1b; cookie默认有跨域限制&#xff0c;不跨域共享和传递&#xff0c;例如&#xff1a; 现代浏览器开始禁…...

Javaweb_xml

文章目录 1.xml是什么&#xff1f;2.xml的用途 1.xml是什么&#xff1f; xml 是可扩展的标记性语言 2.xml的用途 1、用来保存数据&#xff0c;而且这些数据具有自我描述性 2、它还可以做为项目或者模块的配置文件 3、还可以做为网络传输数据的格式&#xff08;现在 JSON 为主…...

http相关知识点

文章目录 长链接http周边会话保持方案1方案2 基本工具postmanFiddlerFiddler的原理 长链接 一张网页实际上可能会有多种元素组成&#xff0c;这也就说明了网页需要多次的http请求。可由于http是基于TCP的&#xff0c;而TCP创建链接是有代价的&#xff0c;因此频繁的创建链接会…...

【SA8295P 源码分析】68 - Android 侧用户层 输入子系统获取 /dev/input/event0 节点数据 代码流程分析

【SA8295P 源码分析】68 - Android 侧用户层 输入子系统获取 /dev/input/event0 节点数据 代码流程分析 一、EventHub.cpp 监听 /dev/input/event0 节点流程二、EventHub.cpp 读取 /dev/input/event0 节点数据流程系列文章汇总见:《【SA8295P 源码分析】00 - 系列文章链接汇总…...

走出迷宫(多组输入bfs)

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 小明现在在玩一个游戏&#xff0c;游戏来到了教学关卡&#xff0c;迷宫是一个N*M的矩阵。 小明的起点在地图中用“S”来表示&#xff0c;终点用“E”来表示&#xff0c;障碍物用“#…...

Linux系统编程-终端、进程组、会话

一、终端的概念 在UNIX系统中&#xff0c;用户通过终端登录系统后得到一个Shell进程&#xff0c;这个终端成为Shell进程的控制终端&#xff08;Controlling Terminal&#xff09;&#xff0c;进程中&#xff0c;控制终端是保存在PCB中的信息&#xff0c;而fork会复制PCB中的信息…...

Linux部分文件操作记录

问题描述 多级文件夹下&#xff0c;有多个同名文件&#xff0c;以及其他无关文件&#xff0c;为了减轻体量&#xff0c;遍历目录&#xff0c;只保留对应文件 首先open terminal here find . -type f \( ! -name algo_imu.bin -a ! -name post_gnss_only_error.log -a ! -name…...

Android系统-进程-Binder2-Java层

引言&#xff1a; 对于Android系统&#xff0c;一般是从java层到native层&#xff0c;再到kernel驱动层&#xff0c;形成一个完整的软件架构。Android系统中的Binder IPC通信机制的整体架构&#xff0c;从java层到底层驱动层是怎么样的一个架构和原理的呢&#xff1f; 概念与…...

体渲染原理及WebGL实现【Volume Rendering】

体渲染&#xff08;Volume Rendering&#xff09;是NeRF神经场辐射AI模型的基础&#xff0c;与传统渲染使用三角形来显示 3D 图形不同&#xff0c;体渲染使用其他方法&#xff0c;例如体积光线投射 (Volume Ray Casting)。本文介绍体渲染的原理并提供Three.js实现代码&#xff…...

VUE3组件

组件基础 {#components-basics} 组件允许我们将 UI 划分为独立的、可重用的部分&#xff0c;并且可以对每个部分进行单独的思考。在实际应用中&#xff0c;组件常常被组织成层层嵌套的树状结构&#xff1a; 这和我们嵌套 HTML 元素的方式类似&#xff0c;Vue 实现了自己的组件…...

【iOS】autoreleasepool

来说一下最近在了解的autoreleasepool吧&#xff0c;我们可能平时书写过许多脑残代码&#xff0c;其有很多的缺陷但是我们可能当时学的比较浅就也不太了解&#xff0c;就像下面这样的&#xff1a; for (int i 0; i < 1000000; i) {NSNumber *num [NSNumber numberWithInt…...

0基础学习VR全景平台篇 第80篇:Insta360 影石如何直播推流

一、下载Insta360 Pro APP 1、手机进入Insta360官网Insta360 | Action Cameras | 360 Cameras | VR Cameras&#xff0c;页面往下滑动到Insta360 Pro2相机处&#xff0c;点击相机图片进入详情页。详情页继续下滑到到手机APP处&#xff0c;根据自己的手机系统选择对应的客户端进…...

大语言模型之三 InstructGPT训练过程

大语言模型 GPT历史文章中简介的大语言模型的的发展史&#xff0c;并且简要介绍了大语言模型的训练过程&#xff0c;本篇文章详细阐述训练的细节和相关的算法。 2020年后全球互联网大厂、AI创业公司研发了不少AI超大模型&#xff08;百亿甚至千亿参数&#xff09;&#xff0c;…...

ChatGPT在自动化报告和数据分析中的应用如何?

ChatGPT在自动化报告和数据分析领域的应用正日益受到关注&#xff0c;这种强大的语言模型不仅可以加速报告生成的过程&#xff0c;还可以辅助数据分析&#xff0c;从而帮助企业和个人更高效地处理信息和做出决策。以下将详细探讨ChatGPT在自动化报告和数据分析中的应用。 **自…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...