僵尸进程
一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被僵尸进程
销毁, 而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是 使进程退出,但
也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)
演示产生僵尸进程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main( void )
{
pid_t pid;
pid = fork();
if( pid < 0 )
{
printf("fail to fork\n");
exit(0);
}
else if( pid == 0 )
{
printf("the child\n");
sleep(5);
printf("done\n");
exit(0);
}
else
printf("the parent\n");
sleep(30);
if(wait(NULL) == -1 )
{
perror("fali to wait");
exit(0);
}
return 0;
}
僵尸进程的危害:
由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束.
那么会不会因为父进程太忙来不及wait子进程,或者说不知道 子进程什么时候结束,而丢失子进程结束时的状态信息呢? 不会。
因为UNⅨ提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是: 在每个进程退出的时候,
内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息
(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。
直到父进程通过wait / waitpid来取时才释放. 但这样就导致了问题,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,
其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程.
此即为僵尸进程的危害,应当避免。
避免僵尸进程的的出现
当父进程在子进程之前结束运行,这是该子进程称为孤儿进程,linux系统中由init进程负责领养所有的孤儿进程,也就是说init进程会成为所有父进程先于自己退出的进程的父进程,作为系统的守护进程,init进程被设计称为永远调用wait函数,也就是说init进程的子进程不会是僵尸进程
演示避免产生僵尸进程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main( void )
{
pid_t pid;
pid = fork();
if( pid < 0 )
{
printf("fail to fork\n");
exit(1);
}
else if( pid == 0 )
{
printf("the child\n");
pid=fork();
if(pid < 0)
{
printf("fail to fork\n");
exit(1);
}
else if(pid == 0)
{
printf("do someting you want!\n");
sleep(5);
printf("done\n");
exit(0);
}
else
exit(0);
}
else
printf("the parent\n");
return 0;
}