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

这篇具有很好参考价值的文章主要介绍了父进程等待子进程退出 / 僵尸进程&孤儿进程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

 文章来源地址https://www.toymoban.com/news/detail-652653.html

僵尸进程

其实上上节的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;
}

运行效果:

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

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

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

“ 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;
}

运行效果:

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

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

通过“ps -aux” 查找1797:

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

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

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

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

 

wait相关函数 

需要添加的库:

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

wait函数原型:

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

 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:

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

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

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

  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:

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程 

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

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

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

可见,此时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:

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

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

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

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

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

 

demo4.c:

使用waitpid函数,并将option设为“WNOHANG”:
waitpid(fork_return,&status,WNOHANG);

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

实现效果:

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

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

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

父进程等待子进程退出 / 僵尸进程&孤儿进程,linux,运维,服务器,c语言,系统编程

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

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

 

 

到了这里,关于父进程等待子进程退出 / 僵尸进程&孤儿进程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】详解进程状态之僵尸进程——孤儿进程

    目录 🌞专栏导读 🌛什么是进程 ⭐什么是PCB?  🌛查看进程  🌛如何通过系统调用查看进程PID 🌛fork 🌞认识进程状态 🌛查看进程状态  🌛R状态  ⭐例如: 🌛S状态  🌛D状态  🌛T状态 🌛t状态: 🌛X状态  🌛Z状态 ⭐僵尸进程 ⭐僵尸进程的危害  🌛孤儿进程 🌟作

    2024年02月13日
    浏览(27)
  • 探索Linux下进程状态 | 僵尸进程 | 孤儿进程

    任何进程在运行时都会有自己的状态 下面的状态在kernel源代码里定义: 常见的几种状态: R运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。 S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断

    2024年04月17日
    浏览(28)
  • 【Linux深入剖析】进程状态---进程僵尸与孤儿

    📙 作者简介 :RO-BERRY 📗 学习方向:致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持 进程 = taskk_stuct + 可执行程序 进程不是一直在运行的 进程放在cpu上也不会一直运行的 它可能在等待某

    2024年03月18日
    浏览(42)
  • 【Linux取经路】探索进程状态之僵尸进程 | 孤儿进程

    进程状态是指在操作系统中,一个进程所处的不同运行状态,进程状态就决定了该进程接下来要执行什么任务。常见的进程状态有以下几种: 新建状态 :进程被创建但还没有被操作系统接受和分配资源。 就绪状态 :进程已经获得了所需的资源,并等待被调度执行。 运行状

    2024年02月12日
    浏览(25)
  • 【Linux】进程状态&&僵尸进程和孤儿进程&&阻塞、挂起和运行

    个人主页 : zxctscl 如有转载请先通知 上一篇博客中提到 【Linux】进程初步理解,这次继续来分享与进程有关的知识。 Linux的进程状态就是struct task_struct内部的一个属性。 为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在

    2024年04月14日
    浏览(23)
  • 【Linux】进程排队的理解&&进程状态的表述&&僵尸进程和孤儿进程的理解

             进程不是一直运行的,进程可能会在等待某种软硬件资源。即使把进程加载到CPU中,也不是一直会运行的。而进程排队,一定是在等待某种软硬件资源(可以是CPU,键盘,磁盘,网卡等等设备......), 排队时是进程的PCB在排队 。 在这里就需要引入一个概念: 一

    2024年03月21日
    浏览(30)
  • 【Linux从入门到放弃】进程状态的理解以及什么是僵尸进程和孤儿进程?

    🧑‍💻作者: @情话0.0 📝专栏:《Linux从入门到放弃》 👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢! 此篇博客依然是在之前的学习基础之上继续探究关于进程的知识。   首先大家可以思考一个问题,当电脑打开一个

    2024年02月13日
    浏览(31)
  • Linux操作命令&静态库和动态库区别&大小端&孤儿僵尸进程

    cd:切换当前目录 ls:查看当前文件与目录 grep:通常与管道符命令一起使用,用于对一些命令的输出进行筛选和加工 cp:复制文件或文件夹 mv:移动文件或文件夹 rm:删除文件或文件夹 ps:查看进程情况 kill:向进程发送信号 tar:对文件进行打包 cat:查看文件内容 top:查看

    2024年02月16日
    浏览(27)
  • 『Linux从入门到精通』第 ⑭ 期 - 僵尸进程?孤儿进程?为什么他有如此惨烈的身世...

    🌸作者简介: 花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。 🌸 专栏简介:本文收录于 Linux从入门到精通 ,本专栏主要内容为本专栏主要内容为Linux的系统性学习,专为小白打造的文章专栏。

    2024年02月16日
    浏览(34)
  • 【Linux】进程的状态(运行、阻塞、挂起)详解,揭开孤儿进程和僵尸进程的面纱,一篇文章万字讲透!!!!进程的学习②

    目录 1.进程排队 时间片 时间片的分配 结构体内存对齐 偏移量补充 对齐规则  为什么会有对齐 2.操作系统学科层面对进程状态的理解 2.1进程的状态理解 ①我们说所谓的状态就是一个整型变量,是task_struct中的一个整型变量 ②.状态决定了接下来的动作 2.2运行状态 2.3 阻塞状

    2024年04月14日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包