zoukankan      html  css  js  c++  java
  • zombie process

    僵尸进程:子进程退出后,父进程还没有回收子进程的资源,那么这个子进程就处于僵尸状态。
    Q1:“资源”是些什么?
    Q2:父进程如何回收子进程的资源?

    内核为每个终止子进程保存了一定量的信息,所以当终止进程的父进程调用wait或waitpid时,可以得到这些信息。
    这些信息至少包括进程ID,该进程的终止状态,以及该进程使用的CPU时间总量.
    内核可以释放终止进程所使用的所有存储区,关闭其所有打开的文件.

    如果编写一个长期运行的程序,他调用fork产生了很多子进程,那么除非父进程等待来取得子进程的终止状态,否则这些子进程终止后就会变成僵尸进程。

    避免僵尸进程的方法
    方法1:调用两次fork可以避免僵尸进程的产生。

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 
     5 int main(void)
     6 {
     7     pid_t pid;
     8 
     9     if ((pid = fork()) < 0)
    10     {
    11         printf("fork error
    ");    
    12         exit(-1);
    13     }
    14     else if (0==pid) /*first child*/
    15     {
    16         printf("1first child pid=%d
    ", getpid());
    17         if ((pid = fork())<0)
    18         {
    19             printf("fork error
    ");    
    20             exit(-1);
    21         }
    22         else if (pid > 0) /*parent from second fork == first child*/
    23         {
    24             printf("2first child pid=%d, first child exit
    ", getpid());
    25             exit(0);//first child exit
    26         }
    27 
    28         printf("second child pid=%d
    ", getpid());
    29         /*I am the second child, my parent become init as soon as my real parent calls exit() in the statement above
    30          * Here's where we'd continue executing, knowing that when we're done, init will reap out status*/
    31         sleep(30);
    32         printf("second child, parent pid = %d, second child exit
    ", getppid());
    33         exit(0);
    34     }
    35 
    36     printf("pararent pid=%d
    ", getpid());
    37     if (waitpid(pid, NULL, 0) != pid) /*wait for first child*/
    38     {
    39         printf("waitpid error
    ");    
    40         exit(-1);
    41     }
    42     printf("parent exit");
    43 
    44 
    45     /*I am the parent(the original process); I continue executing, knowing that I'm not the parent of the second child*/
    46 
    47     exit(0);
    48 }


    方法2:当SIGCHLD的处理方式是系统默认时,父进程调用了wait()以避免僵尸进程的产生,此方法中,父进程阻塞。

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <sys/wait.h>
     4 #include <errno.h>
     5 #include <signal.h>
     6 
     7 void print_exit(int status)
     8 {
     9     if (WIFEXITED(status))
    10         printf("normal termination, exit status = %d
    ", WEXITSTATUS(status));
    11     else if (WIFSIGNALED(status))
    12         printf("abnormal termination, signal number = %d%s
    ", WTERMSIG(status),
    13 #ifdef WCOREDUMP
    14         WCOREDUMP(status) ? ("core file generated") : (""));
    15 #else
    16     "");
    17 #endif
    18     else if (WIFSTOPPED(status))
    19         printf("child stopped, signal number=%d
    ", WSTOPSIG(status));
    20 }
    21 
    22 void sig_child(int signo)
    23 {
    24     int status;
    25     int ret;
    26     ret = wait(&status);
    27     printf("pid:%d, res:%d, status=%d, %s
    ", getpid(), ret, status, strerror(errno));
    28     print_exit(status);
    29 }
    30 
    31 void sig_usr(int signo)
    32 {
    33     if (signo == SIGUSR1)
    34         printf("received SIGUSR1
    ");
    35     else if (signo == SIGUSR2)
    36         printf("received SIGUSR2
    ");
    37     else
    38         printf("received signal %d
    ", signo);
    39 }
    40 
    41 int main(int argc, char** argv)
    42 {
    43     pid_t pid;
    44     int status;
    45     int ret;
    46 
    47     if ((pid=fork()) < 0)
    48     {
    49         printf("fork error
    ");
    50         return -1;
    51     }
    52     else if (pid == 0)
    53     {
    54         printf("child exit
    ");
    55         return 0;
    56     }
    57     else
    58     {
    59         //printf("parent sleep(100)
    ");
    60         //sleep(100);
    61         ret = wait(&status);
    62         print_exit(status);
    63         printf("parent exit
    ");
    64     }
    65 
    66 
    67     exit(0);
    68 }


    方法3:当SIGCHLD的处理方式是捕获时,在其信号处理程序中调用wait()函数以避免僵尸进程的产生,此方法中,父进程不阻塞。

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <sys/wait.h>
     4 #include <errno.h>
     5 #include <signal.h>
     6 
     7 void print_exit(int status)
     8 {
     9     if (WIFEXITED(status))
    10         printf("normal termination, exit status = %d
    ", WEXITSTATUS(status));
    11     else if (WIFSIGNALED(status))
    12         printf("abnormal termination, signal number = %d%s
    ", WTERMSIG(status),
    13 #ifdef WCOREDUMP
    14         WCOREDUMP(status) ? ("core file generated") : (""));
    15 #else
    16     "");
    17 #endif
    18     else if (WIFSTOPPED(status))
    19         printf("child stopped, signal number=%d
    ", WSTOPSIG(status));
    20 }
    21 
    22 void sig_child(int signo)
    23 {
    24     int status;
    25     int ret;
    26     ret = wait(&status);
    27     printf("pid:%d, res:%d, status=%d, %s
    ", getpid(), ret, status, strerror(errno));
    28     print_exit(status);
    29 }
    30 
    31 void sig_usr(int signo)
    32 {
    33     if (signo == SIGUSR1)
    34         printf("received SIGUSR1
    ");
    35     else if (signo == SIGUSR2)
    36         printf("received SIGUSR2
    ");
    37     else
    38         printf("received signal %d
    ", signo);
    39 }
    40 
    41 int main(int argc, char** argv)
    42 {
    43     pid_t pid;
    44     struct sigaction act, oact;
    45     int status;
    46     int ret;
    47 
    48     act.sa_handler = sig_child;
    49     sigemptyset(&act.sa_mask);
    50     //act.sa_flags = 0|SA_NOCLDWAIT;
    51     sigaction(SIGCHLD, &act, &oact);
    52 
    53     if ((pid=fork()) < 0)
    54     {
    55         printf("fork error
    ");
    56         return -1;
    57     }
    58     else if (pid == 0)
    59     {
    60         printf("child exit
    ");
    61         return 0;
    62     }
    63     else
    64     {
    65         printf("parent sleep(100)
    ");
    66         sleep(100);
    67         printf("parent exit
    ");
    68     }
    69 
    70 
    71     exit(0);
    72 }

    从打印中可以看出,信号处理程序由父进程调用
    方法4:设置SIGCHLD为SA_NOCLDWAIT,当子进程终止时,不创建僵尸进程。父进程中不需调用wait。

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <sys/wait.h>
     4 #include <errno.h>
     5 #include <signal.h>
     6 
     7 void print_exit(int status)
     8 {
     9     if (WIFEXITED(status))
    10         printf("normal termination, exit status = %d
    ", WEXITSTATUS(status));
    11     else if (WIFSIGNALED(status))
    12         printf("abnormal termination, signal number = %d%s
    ", WTERMSIG(status),
    13 #ifdef WCOREDUMP
    14         WCOREDUMP(status) ? ("core file generated") : (""));
    15 #else
    16     "");
    17 #endif
    18     else if (WIFSTOPPED(status))
    19         printf("child stopped, signal number=%d
    ", WSTOPSIG(status));
    20 }
    21 
    22 void sig_usr(int signo)
    23 {
    24     if (signo == SIGUSR1)
    25         printf("received SIGUSR1
    ");
    26     else if (signo == SIGUSR2)
    27         printf("received SIGUSR2
    ");
    28     else
    29         printf("received signal %d
    ", signo);
    30 }
    31 
    32 int main(int argc, char** argv)
    33 {
    34     pid_t pid;
    35     struct sigaction act, oact;
    36     int status;
    37     int ret;
    38 
    39     act.sa_handler = sig_usr;
    40     sigemptyset(&act.sa_mask);
    41     act.sa_flags = 0|SA_NOCLDWAIT;
    42     sigaction(SIGCHLD, &act, &oact);
    43 
    44     if ((pid=fork()) < 0)
    45     {
    46         printf("fork error
    ");
    47         return -1;
    48     }
    49     else if (pid == 0)
    50     {
    51         printf("child exit
    ");
    52         return 0;
    53     }
    54     else
    55     {
    56         printf("parent sleep(100)
    ");
    57         sleep(100);
    58         //ret = wait(&status);
    59         //print_exit(status);
    60         printf("parent exit
    ");
    61     }
    62 
    63 
    64     exit(0);
    65 }
  • 相关阅读:
    Canvas
    Web API 接口-JavaScript全部api接口文档
    编程中的命名设计那点事
    线程池的使用
    SRW锁的使用
    内存屏障
    VC用Beep整几首歌听听~~~
    简单的多线程并发同步演示(4种同步方法)
    C语言生成程序问题
    文件操作(输出倒数第二行、逆序输出)
  • 原文地址:https://www.cnblogs.com/black-mamba/p/6937375.html
Copyright © 2011-2022 走看看