1. 程式人生 > >呼叫 fork 兩次以避免僵死程序

呼叫 fork 兩次以避免僵死程序

               

 當我們只fork()一次後,存在父程序和子程序。這時有兩種方法來避免產生殭屍程序:

  • 父程序呼叫waitpid()等函式來接收子程序退出狀態。
  • 父程序先結束,子程序則自動託管到Init程序(pid = 1)。

      目前先考慮子程序先於父程序結束的情況:     

  • 若父程序未處理子程序退出狀態,在父程序退出前,子程序一直處於殭屍程序狀態。
  • 若父程序呼叫waitpid()(這裡使用阻塞呼叫確保子程序先於父程序結束)來等待子程序結束,將會使父程序在呼叫waitpid()後進入睡眠狀態,只有子程序結束父程序的waitpid()才會返回。 如果存在子程序結束,但父程序還未執行到waitpid()的情況,那麼這段時期子程序也將處於殭屍程序狀態。

      由此,可以看出父程序與子程序有父子關係,除非保證父程序先於子程序結束或者保證父程序在子程序結束前執行waitpid(),子程序均有機會成為殭屍程序。那麼如何使父程序更方便地建立不會成為殭屍程序的子程序呢?這就要用兩次fork()了。

      父程序一次fork()後產生一個子程序隨後立即執行waitpid(子程序pid, NULL, 0)來等待子程序結束,然後子程序fork()後產生孫子程序隨後立即exit(0)。這樣子程序順利終止(父程序僅僅給子程序收屍,並不需要子程序的返回值),然後父程序繼續執行。這時的孫子程序由於失去了它的父程序(即是父程序的子程序),將被轉交給Init程序託管。於是父程序與孫子程序無繼承關係了,它們的父程序均為Init,Init程序在其子程序結束時會自動收屍,這樣也就不會產生殭屍程序了。

#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);     }