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

posted @ 2021-04-16 16:01  Ivessas  阅读(242)  评论(0)    收藏  举报