Linux僵尸进程的三种处理方式

3.1分析以下程序,会有僵尸进程出现吗?后台运行该程序,前台用ps命令查看进程,判断是否出现僵尸进程,如果出现,请用三种方法(wait/waitpid,两次fork,捕捉信号SIGCHLD)修改程序处理僵尸进程。

#include<stdio.h>

#include<stdlib.h>

#include<sys/types.h>

#include<sys/wait.h>

    main()

{int pid;

 if ((pid=fork())==0)

    { sleep(2);printf("child process %d  exit\n",getpid());exit(0);}

 else

  { printf("hello child\n");

    while(1){ sleep(1); };

   }

}

 

先让我们以一段资料来了解一下有关僵尸进程的资料.

从以上资料中我们可以看出,若不对僵尸进程采取措施处理,则会浪费一定的内存空间.

我们先运行一下下述程序,并查看运行结果.

#include<stdio.h>

#include<stdlib.h>

#include<sys/types.h>

#include<sys/wait.h>

int main()

{

    int pid;

    pid = fork();

    if(pid == 0) //son process

     {

        sleep(2);

        printf("child process %d  exit\n",getpid());

        exit(0);

     }

    else if(pid > 0) //father process

     { 

        printf("hello child\n");

        while(1)

          {

            sleep(1);

          }

     }

    return 0;

}

为什么这里产生了僵尸进程呢?原来是在子进程结束后,父进程还一直处于while(1)循环中:正是由于父进程没有结束,所以无人来回收子进程的PCB.如此一来,子进程就成为了僵尸进程.

我们再来推广一下,若这里父进程不是陷入while(1)循环中无法跳出,而是在子进程结束后还有很长时间的工作要做.如果是这样,那么在父进程做完这很长时间的工作前,子进程结束后要保持僵尸态,并占用一定内存空间.一个僵尸进程占用的内存空间的确微不足道,但倘若父进程fork()出大量的子进程而这些子进程都在父进程结束前的某个时刻成为了僵尸进程,那么这对系统资源的消耗将是需要考虑的.

 

我们再来看一下什么是init进程.

 

有了上面对大量僵尸进程占用内存空间的考虑,接下来我们看一下该如何处理僵尸进程.

办法1:两次fork().

先给出一个会产生僵尸进程的程序,运行后观察结果.

#include<stdio.h>

#include<stdlib.h>

#include<sys/types.h>

#include<sys/wait.h>

int main()

{

    int pid;

    pid = fork();

    if(pid > 0)//father process

     {

      int i = 1;

      while(i <= 12)

      {

        sleep(1);

        i += 1;

          }

     }

    else if(pid == 0)//son process

     {

       int j = 1;

       while(j <= 4)

        {

         sleep(1);

         j += 1;

            }

       exit(0);

     }  

    return 0;

}

通过结果可以清晰地看出,当大约4s后子进程结束,此时父进程还有大约8s的时间才能结束,这就导致在4 ~ 12s间,子进程成为僵尸进程.

 

下面的程序是基于上面改造的,即运用两次fork()来避免僵尸进程的出现.

#include<stdio.h>

#include<stdlib.h>

#include<sys/types.h>

#include<sys/wait.h>

int main()

{

    int pid;

    pid = fork();

    if(pid > 0)//father process

     {

      wait(0);//waiting for the end of son process

      int j = 1;

      while(j <= 12)

      {

        sleep(1);

        j ++;

      }

     }

    else if(pid == 0)//son process

     {

      int pid2;

      pid2 = fork();

      if(pid2 > 0)//son process

      {

        exit(0);

      }

      else if(pid2 == 0)//grandson process

      {

        int i = 1;

        while(i <= 4)

        {

             sleep(1);

             i ++;

        }

        exit(0);

      }

     }

    return 0;

}

 

2-2:signal()函数

再让我们回顾一下什么是僵尸进程.

那么为什么要设置僵尸进程?

再来回顾一下避免僵尸进程的几种方式.

通过上述资料我们可以得知,通过signal(SIGCHLD, SIG_LGN)通知内核对子进程的结束不关心,由内核回收. SIGCHLD信号是子进程退出时向父进程发送的.

 

2-3:wait()

#include<stdio.h>

#include<stdlib.h>

#include<sys/types.h>

#include<sys/wait.h>

int main()

{

    int pid;

    pid = fork();

    if(pid > 0)//father process

     {

      wait(0);//waiting for the end of son process

      int i = 1;

      while(i <= 10)

      {

        sleep(1);

        i ++;

      }

     }

    else if(pid == 0)//son process

     {

      int j = 1;

      while(j <= 5)

      {

        sleep(1);

        j ++;

      }

     exit(0);

     }

    return 0;

}

 

2-4 waitpid()

#include<stdio.h>

#include<stdlib.h>

#include<sys/types.h>

#include<sys/wait.h>

int main()

{

    int pid;

    pid = fork();

    if(pid > 0)//father process

     {

      waitpid(-1, NULL, 0);//waiting for the end of son process

      int i = 1;

      while(i <= 10)

      {

        sleep(1);

        i ++;

      }

     }

    else if(pid == 0)//son process

     {

      int j = 1;

      while(j <= 5)

      {

        sleep(1);

        j ++;

      }

     exit(0);

     }

    return 0;

}

猜你喜欢

转载自blog.csdn.net/weixin_42048463/article/details/94716046