总结:
僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
害处:
僵尸进程:占用系统资源,如果很多,则会严重影响服务器的性能
孤儿进程:不会占用系统资源
只要老爹不等wait(sys/wait.h)儿子,儿子都将成为孤魂野鬼zombie,unix中默认老爹总是想看儿子死后的状态(以便报仇)
if 老爹比儿子先再见
儿子将被init进程收养,最后的结果是zombie儿子彻底再见,系统资源释放
else
{
儿子的zombie将一直存在,系统资源占用...
if 老爹dead
儿子将被init(id = 1)收养,最后的结果是zombie儿子彻底再见,系统资源释放
else
类似的儿子zombie越来越多,系统就等死了!!!
}
如何防止僵尸进程?
首先明白如何产生僵尸进程:
1、子进程结束后向父进程发出SIGCHLD信号,父进程默认忽略了它
2、父进程没有调用wait()或waitpid()函数来等待子进程的结束
因此,防止的方法有:
第一种方法: 捕捉SIGCHLD信号,并在信号处理函数里面调用wait函数
int main(int argc, char **argv)
{
...
Signal(SIGCHLD, sig_chld);
for(;}
...
}
void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) >; 0)
printf("child %d terminated/n", pid);
return;
}
第二种方法:两次fork():
在《Unix 环境高级编程》里关于这个在8.6节有非常清楚的说明。如果一个进程要fork一个子进程,但不要求它等待子进程终止,也不希望子进程处于僵死状态直到父进程终止,实现这一要求的诀窍是调用fork两次。程序8 - 5实现了这一点。在第二个子进程中调用s l e e p以保证在打印父进程I D时第一个子进程已终止。在f o r k之后,父、子进程都可继续执行——我们无法预知哪一个会先执行。如果不使第二个子进程睡眠,则在f o r k之后,它可能比其父进程先执行,于是它打印的父进程I D将是创建它的父进程,而不是i n i t进程(进程ID 1)。
#include <sys/types.h>
#include <sys/wait.h>
#include "ourhdr.h"
int
main(void)
{
pid_t pid;
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) { /* first child */
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid > 0)
exit(0); /* parent from second fork == first child */
/* We're the second child; our parent becomes init as soon
as our real parent calls exit() in the statement above.
Here's where we'd continue executing, knowing that when
we're done, init will reap our status. */
sleep(2);
printf("second child, parent pid = %d/n", getppid());
exit(0);
}
if (waitpid(pid, NULL, 0) != pid) /* wait for first child */
err_sys("waitpid error");
/* We're the parent (the original process); we continue executing,
knowing that we're not the parent of the second child. */
exit(0);
}