Unix通过fork两次避免僵尸进程
在阅读APUE 8.6 节时对fork两次避免僵尸进程有点不是很理解,在此记录一下。
首先review一下概念:
-
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
-
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
对于APUE中的例子代码:
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
{
fprintf(stderr,"Fork error!/n");
exit(-1);
}
else if (pid == 0) /* first child */
{
if ((pid = fork()) < 0)
{
fprintf(stderr,"Fork error!/n");
exit(-1);
}
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 */
{
fprintf(stderr,"Waitpid error!/n");
exit(-1);
}
/*
* We're the parent (the original process); we continue executing,
* knowing that we're not the parent of the second child.
*/
exit(0);
}
这里能够避免僵尸进程的原因是:
父进程A调用fork
产生子进程B,然后调用wait
或者waitpid
等待子进程B的结束,进程B调用fork产生子进程C,使B在C结束之前结束,此时C变成了孤儿进程由init
领养,这样A和C就没有了继承关系,互不干扰,各施其责。这样就避免了僵尸进程的问题了。
Reference
- https://blog.csdn.net/wangjian20095356/article/details/38779723?utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.control
- https://monkeysayhi.github.io/2018/12/05/浅谈Linux僵尸进程与孤儿进程/
- https://blog.csdn.net/macky0668/article/details/3185141?utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromMachineLearnPai2~default-1.control