linux c之孤儿进程与僵尸进程[总结]

转载地址:http://www.cnblogs.com/Anker/p/3271773.html


1、前言


  之前在看《unix环境高级编程》第八章进程时候,提到孤儿进程和僵尸进程,一直对这两个概念比较模糊。今天被人问到什么是孤儿进程和僵尸进程,会带来什么问题,怎么解决,我只停留在概念上面,没有深入,倍感惭愧。晚上回来google了一下,再次参考APUE,认真总结一下,加深理解。



2、基本概念


  我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

  孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

  僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。



3、问题及危害


  unix提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是: 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放。 但这样就导致了问题,如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

  孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

  任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。  如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。

  僵尸进程危害场景:

  例如有个进程,它定期的产 生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问,这样,系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用ps命令查看的话,就会看到很多状态为Z的进程。 严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。



4、孤儿进程和僵尸进程测试


孤儿进程测试程序如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>int main()
{pid_t pid;//创建一个进程pid = fork();//创建失败if (pid < 0){perror("fork error:");exit(1);}//子进程if (pid == 0){printf("I am the child process.\n");//输出进程ID和父进程IDprintf("pid: %d\tppid:%d\n",getpid(),getppid());printf("I will sleep five seconds.\n");//睡眠5s,保证父进程先退出sleep(5);printf("pid: %d\tppid:%d\n",getpid(),getppid());printf("child process is exited.\n");}//父进程else{printf("I am father process.\n");//父进程睡眠1s,保证子进程输出进程idsleep(1);printf("father process is  exited.\n");}return 0;
}


5 僵尸进程测试程序如下所示:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>int main()
{pid_t pid;pid = fork();if (pid < 0){perror("fork error:");exit(1);}else if (pid == 0){printf("I am child process.I am exiting.\n");exit(0);}printf("I am father process.I will sleep two seconds\n");//等待子进程先退出sleep(2);//输出进程信息system("ps -o pid,ppid,state,tty,command");printf("father process is exiting.\n");return 0;
}


僵尸进程测试2:父进程循环创建子进程,子进程退出,造成多个僵尸进程,程序如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>int main()
{pid_t  pid;//循环创建子进程while(1){pid = fork();if (pid < 0){perror("fork error:");exit(1);}else if (pid == 0){printf("I am a child process.\nI am exiting.\n");//子进程退出,成为僵尸进程exit(0);}else{//父进程休眠20s继续创建子进程sleep(20);continue;}}return 0;
}



6、僵尸进程解决办法


(1)通过信号机制


  子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。测试程序如下所示:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>static void sig_child(int signo);int main()
{pid_t pid;//创建捕捉子进程退出信号signal(SIGCHLD,sig_child);pid = fork();if (pid < 0){perror("fork error:");exit(1);}else if (pid == 0){printf("I am child process,pid id %d.I am exiting.\n",getpid());exit(0);}printf("I am father process.I will sleep two seconds\n");//等待子进程先退出sleep(2);//输出进程信息system("ps -o pid,ppid,state,tty,command");printf("father process is exiting.\n");return 0;
}static void sig_child(int signo)
{pid_t        pid;int        stat;//处理僵尸进程while ((pid = waitpid(-1, &stat, WNOHANG)) >0)printf("child %d terminated.\n", pid);
}

(2)fork两次

  《Unix 环境高级编程》8.6节说的非常详细。原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。测试程序如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>int main()
{pid_t  pid;//创建第一个子进程pid = fork();if (pid < 0){perror("fork error:");exit(1);}//第一个子进程else if (pid == 0){//子进程再创建子进程printf("I am the first child process.pid:%d\tppid:%d\n",getpid(),getppid());pid = fork();if (pid < 0){perror("fork error:");exit(1);}//第一个子进程退出else if (pid >0){printf("first procee is exited.\n");exit(0);}//第二个子进程//睡眠3s保证第一个子进程退出,这样第二个子进程的父亲就是init进程里sleep(3);printf("I am the second child process.pid: %d\tppid:%d\n",getpid(),getppid());exit(0);}//父进程处理第一个子进程退出if (waitpid(pid, NULL, 0) != pid){perror("waitepid error:");exit(1);}exit(0);return 0;
}






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

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

相关文章

留学申请中,你们怎么老让我做科研啊?

全世界只有3.14 % 的人关注了爆炸吧知识太太太太闹心了&#xff0c;真的&#xff0c;留学申请准备这准备那已经很糟心了&#xff0c;怎么总看到让我做科研的广告啊&#xff0c;刚开始看看没在意&#xff0c;越来越多越来越多&#xff0c;不做都感觉赶不上潮流&#xff0c;不做就…

C# Dispose模式

目的为了及时释放宝贵的非托管资源和托管资源&#xff0c;并且保证资源在被 gc 回收的时候可以正确释放资源&#xff0c;同时兼顾执行效率。必须遵循的事实1 . 托管资源释放&#xff1a;  由另一线程的 gc 进行释放&#xff0c;当托管的对象没有被引用时&#xff0c;就会在“…

在ASP.NET项目中使用CKEditor +CKFinder实现图片上传功能

前言 之前的项目中一直使用的是FCKeditor&#xff0c;昨天突然有个想法&#xff1a;为什么不试一下新的CKEditor呢&#xff1f;于是花了大半天的时间去学习它的用法&#xff0c;现在把我的学习过程与大家分享一下。 谈起FCKeditor&#xff0c;相信没几个Web程序员不知道的吧。不…

linux之内核剖析

Linux 内核简介 现在让我们从一个比较高的高度来审视一下 GNU/Linux 操作系统的体系结构。您可以从两个层次上来考虑操作系统&#xff0c;如图 2 所示。 图 2. GNU/Linux 操作系统的基本体系结构 上面是用户&#xff08;或应用程序&#xff09;空间。这是用户应用程序执行的地…

linux笔记 3-4 SMTP,.配置电子邮件传输

***************4.配置电子邮件传输*****************##1.基本电子邮件配置##配置dns服务&#xff0c;添加MX记录两台服务器分别配置 /etc/postfix/main.cf文件myhostname--主机名mydomain--域名myorigin--重写本地发布的电子邮件,使其显示为来自该域。这样有助于确保响应返回入…

希尔排序算法的实现

希尔排序(Shell Sort)是插入排序的一种&#xff0c;它是针对直接插入排序算法的改进。该方法又称缩小增量排序&#xff0c;因DL&#xff0e;Shell于1959年提出而得名。 希尔排序实质上是一种分组插入方法。它的基本思想是&#xff1a;对于n个待排序的数列&#xff0c;取一个小于…

linux c之信号signal处理机制

最近同事的程序设计过程中用到了Linux的signal机制&#xff0c;从而引发了我对Linux中signal机制的思考。Signal机制在Linux中是一个非常常用的进程间通信机制&#xff0c;很多人在使用的时候不会考虑该机制是具体如何实现的。signal机制可以被理解成进程的软中断&#xff0c;因…

技术分享 | 微服务模式下如何高效进行API测试

导读&#xff1a;微服务架构下&#xff0c;API 测试的最大挑战来自于庞大的测试用例数量&#xff0c;以及微服务之间的相互耦合。基于这种挑战&#xff0c;如何进行高效的API测试&#xff0c;选择什么样的方式就比较重要&#xff0c;此文主要是采用契约测试的方法来对微服务模式…

由CloudStack项目引起的ESXI嵌套虚拟化引起的二级虚拟机无法被访问

关于这个问题&#xff0c;主要以文字描述为主&#xff0c;最终解决方法其实就一个步骤。问题描述&#xff1a;某客户需要部署某企业的云平台&#xff0c;但是由于年前没有足够的物理机资源&#xff0c;所以提供的资源均为虚拟机&#xff0c;现在让我们做技术评估。其实观察整个…

美女的床真的好难爬......

1 地中海式茂密&#xff1f;▼2 阴着呐▼3 拜拜了您呐▼4 草莓从哪里来▼5 爷青结系列▼6 没点才艺还住不了酒店了▼7 美女的床果真很难爬(真从500平大床中醒来)▼8 数学能有多有趣▼你点的每个赞&#xff0c;我都认真当成了喜欢

控制器方法错误处理

错误处理一直是开发维护阶段需要重点关注的一块&#xff0c;控制器中方法原则上都需要处理错误。 1、添加BaseController 路径&#xff1a;nweb\src\main\java\com\nankang\cati\nweb\controller\BaseController.java 所有的控制器都继承BaseController 2、使用&#xff1a; 1&…

EF Core 6 新功能汇总(一)

在这篇文章中&#xff0c;你将看到 EF Core 6 中的十个新功能&#xff0c;包括新的特性标注&#xff0c;对时态表、稀疏列的支持&#xff0c;以及其他新功能。1Unicode 特性在 EF Core 6.0 中&#xff0c;新的 UnicodeAttribute 允许你将一个字符串属性映射到一个非 Unicode 列…

DS5020配置集群存储

一、方案设计 计划给某公司服务器制作集群&#xff0c;存储划分大致如下&#xff1a; 1、 将存储磁盘制作为raid5&#xff1b; 2、 划分两个Storage Partition给两类集群使用&#xff0c;一类为数据库服务&#xff0c;一类为各种应用服务 二、存储的连接 1、存储的简介 Serial …

RequireJS首次加载偶尔失败

现象&#xff1a;第一次加载JS文件&#xff0c;首次加载偶尔失败&#xff1b; 原因&#xff1a;require([jquery, operamasks, zTree, jQueryCookie]&#xff0c;中前后引用同步加载&#xff1b; 解决方式&#xff1a;shim声明前置加载&#xff1b; 配置如下&#xff1a; requi…

linux之file命令总结

解释&#xff1a; file是通过查看文件的头部内容&#xff0c;来获取文件的类型使用file命令可以知道某个文件究竟是二进制&#xff08;ELF格式&#xff09;的可执行文件, 还是Shell Script文件&#xff0c;或者是其它的什么格式。 file能识别的文件类型&#xff1a;目录、Shel…

优化.NET 应用程序 CPU 和内存的11 个实践

https://michaelscodingspot.com/cpu-bound-memory-bound/优化.NET 应用程序 CPU 和内存的11 个实践凡事都有其限度&#xff0c;对吧&#xff1f;汽车只能开这么快&#xff0c;进程只能使用这么多内存&#xff0c;程序员只能喝这么多咖啡。我们的生产力受到资源的限制&#xff…

陈省身:三角形内角和不等于180°

全世界只有3.14 % 的人关注了爆炸吧知识三角形外角和为360作为公认的劳模&#xff0c;平日里&#xff0c;超模君不但要码字&#xff0c;工作之余还要监督表妹做作业&#xff0c;也难怪表妹成绩总是能名列前茅。今天表妹做作业时&#xff0c;遇到一道判断题&#xff1a;“三角形…

跟我学PHP第二篇- 配置Mysql以及PHP WampServer篇(1)

大家好&#xff0c;昨天我给大家介绍了如何去安装ZEND STUDIO&#xff0c;下面昨天文章的链接&#xff1a; http://www.cnblogs.com/kmsfan/p/zendStudio.html 本节为配置的第一部分&#xff0c;还没有讲完全部&#xff0c;因为个人工作比较忙&#xff0c;没有一整天时间写博客…