父进程等待子进程退出 / 僵尸进程孤儿进程
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:

- option如果设置为“WNOHANG”,则 若由PID指定的子进程不是立刻可用的,则waitpid不阻塞,此时其返回值为0
- option如果设置为“WUNTRACED”,则 若某实现支持作业控制,而由PID指定的任一子进程已处于暂停状态,并且其状态自暂停以来还未报告过,则返回其状态,WIFSTOPPED宏确定返回值是否对应于一个暂停子进程
- 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:父进程为什么要等待子进程退出? A:回顾创建子进程的目的,就是让子进程去处理一些事情,那么“事情干完了没有”这件事,父进程需要知道并收集子进程的退出状态。子进程的退出状态如果不被收集,…...
【LeetCode 75】第二十六题(394)字符串解码
目录 题目: 示例: 分析: 代码运行结果: 题目: 示例: 分析: 给我们字符串,让我们解码,那么该怎么解码呢,被括号【】包裹起来的字符串需要扩展成括号左边第…...
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++实现
题目链接: 素数判定https://www.nowcoder.com/share/jump/437195121691718831561 描述 给定一个数n,要求判断其是否为素数(0,1,负数都是非素数)。 输入描述: 测试数据有多组,每组输入一个数…...
iOS_crash文件的获取及符号化(解析)
文章目录 1. 使用 symbolicatecrash 解析 .ips 文件: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、新建工程,进行基本配置 2、配置定时器TIM2 1)定时器计算公式:(以下两条公式相同) Tout ((ARR1) * PSC1)) / Tclk TimeOut ((Prescaler 1) * (Period 1)) / TimeClockFren Tout TimeOut&…...
网络请求中,token和cookie有什么区别
HTTP无状态,每次请求都要携带cookie,以帮助识别用户身份; 服务端也可以向客户端set-cookie,cookie大小限制为4kb; cookie默认有跨域限制,不跨域共享和传递,例如: 现代浏览器开始禁…...
Javaweb_xml
文章目录 1.xml是什么?2.xml的用途 1.xml是什么? xml 是可扩展的标记性语言 2.xml的用途 1、用来保存数据,而且这些数据具有自我描述性 2、它还可以做为项目或者模块的配置文件 3、还可以做为网络传输数据的格式(现在 JSON 为主…...
http相关知识点
文章目录 长链接http周边会话保持方案1方案2 基本工具postmanFiddlerFiddler的原理 长链接 一张网页实际上可能会有多种元素组成,这也就说明了网页需要多次的http请求。可由于http是基于TCP的,而TCP创建链接是有代价的,因此频繁的创建链接会…...
【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)
链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 小明现在在玩一个游戏,游戏来到了教学关卡,迷宫是一个N*M的矩阵。 小明的起点在地图中用“S”来表示,终点用“E”来表示,障碍物用“#…...
Linux系统编程-终端、进程组、会话
一、终端的概念 在UNIX系统中,用户通过终端登录系统后得到一个Shell进程,这个终端成为Shell进程的控制终端(Controlling Terminal),进程中,控制终端是保存在PCB中的信息,而fork会复制PCB中的信息…...
Linux部分文件操作记录
问题描述 多级文件夹下,有多个同名文件,以及其他无关文件,为了减轻体量,遍历目录,只保留对应文件 首先open terminal here find . -type f \( ! -name algo_imu.bin -a ! -name post_gnss_only_error.log -a ! -name…...
Android系统-进程-Binder2-Java层
引言: 对于Android系统,一般是从java层到native层,再到kernel驱动层,形成一个完整的软件架构。Android系统中的Binder IPC通信机制的整体架构,从java层到底层驱动层是怎么样的一个架构和原理的呢? 概念与…...
体渲染原理及WebGL实现【Volume Rendering】
体渲染(Volume Rendering)是NeRF神经场辐射AI模型的基础,与传统渲染使用三角形来显示 3D 图形不同,体渲染使用其他方法,例如体积光线投射 (Volume Ray Casting)。本文介绍体渲染的原理并提供Three.js实现代码ÿ…...
VUE3组件
组件基础 {#components-basics} 组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成层层嵌套的树状结构: 这和我们嵌套 HTML 元素的方式类似,Vue 实现了自己的组件…...
【iOS】autoreleasepool
来说一下最近在了解的autoreleasepool吧,我们可能平时书写过许多脑残代码,其有很多的缺陷但是我们可能当时学的比较浅就也不太了解,就像下面这样的: 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,页面往下滑动到Insta360 Pro2相机处,点击相机图片进入详情页。详情页继续下滑到到手机APP处,根据自己的手机系统选择对应的客户端进…...
大语言模型之三 InstructGPT训练过程
大语言模型 GPT历史文章中简介的大语言模型的的发展史,并且简要介绍了大语言模型的训练过程,本篇文章详细阐述训练的细节和相关的算法。 2020年后全球互联网大厂、AI创业公司研发了不少AI超大模型(百亿甚至千亿参数),…...
ChatGPT在自动化报告和数据分析中的应用如何?
ChatGPT在自动化报告和数据分析领域的应用正日益受到关注,这种强大的语言模型不仅可以加速报告生成的过程,还可以辅助数据分析,从而帮助企业和个人更高效地处理信息和做出决策。以下将详细探讨ChatGPT在自动化报告和数据分析中的应用。 **自…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...

