• 第十九篇:处理僵尸进程的两种经典方法


    前言

           如果父进程没有结束,而子进程终止了。那么在父进程调用 wait 函数回收这个子进程或者父进程终止以前,这个子进程将一直是僵尸进程

           本文将提供两种方法处理这个问题。

    方法一:父进程回收法

           wait函数将使其调用者阻塞,直到其某个子进程终止。故父进程可调用wait函数回收其僵尸子进程。除此之外,waitpid函数提供更为详尽的功能( 增加了非阻塞功能以及指定等待功能 ),请读者自行查阅相关资料。

    代码实现

     1 #include <unistd.h>
     2 #include <sys/wait.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 int main()
     7 {
     8     int pid;
     9     int *status;
    10 
    11     printf("%s
    ", "启动父进程");
    12 
    13     if ((pid = fork()) < 0) {
    14         printf("%s
    ", "创建子进程失败");
    15         exit(1);
    16     }
    17     else 
    18         if (pid ==0) {
    19             printf("%s
    ", "进入子进程");
    20             sleep(4);
    21             // 终止子进程
    22             exit(0);
    23         }
    24     else {
    25         // 进入父进程
    26         // 回收僵尸子子进程
    27         wait(status);
    28         printf("%s
    ", "回收完毕");
    29     }
    30 
    31     exit(0);
    32 }

    运行测试

           

    结果分析

           第三行的“回收完毕”是在程序执行四秒后才显示的。这说明尽管我将子进程阻塞了4秒,父进程并不会先于子进程终止。因为它调用了wait函数,故需要等待一个子进程结束并将其回收,否则就一直阻塞在那里。

    方法二:init进程回收法

           上面的这种解决方案需要父进程去等待子进程,但在很多情况下,这并不合适,因为父进程也许还有其他任务要做,不能阻塞在这里。在讲述下面这种不用父进程等待就能完成回收子进程的方法之前,先请明白以下两个概念:

           1. 如果父进程先于子进程结束,那么子进程的父进程自动改为 init 进程。

           2. 如果 init 的子进程结束,则 init 进程会自动回收其子进程的资源而不是让它变成僵尸进程。

    代码实现

     1 #include "apue.h"
     2 #include <sys/wait.h>
     3 
     4 int
     5 main(void)
     6 {
     7     pid_t    pid;
     8 
     9     if ((pid = fork()) < 0) {    // 创建第一个子进程
    10         err_sys("fork error");
    11     } else if (pid == 0) {    // 进入第一个子进程
    12         if ((pid = fork()) < 0)    // 创建第二个子进程
    13             err_sys("fork error");
    14         else if (pid > 0) // 进入第一个子进程 
    15             exit(0);    // 终止第一个子进程    
    16         // 第二个子进程在睡眠2S后才执行,这样一般情况下第一个子进程会先终止。
    17         sleep(2);
    18         // 这时,第一个子进程肯定终止了,那么它的父进程就自动变成了init。
    19         printf("second child, parent pid = %d
    ", getppid());
    20         exit(0);
    21     }
    22 
    23     // 父进程等待并回收第一个子进程
    24     if (waitpid(pid, NULL, 0) != pid)    
    25         err_sys("waitpid error");
    26 
    27     // 父进程执行到这里以后,可以退出,也可以执行其他的任务。
    28     // 对于刚才那第二个子进程,它继承了父进程的资源,同时它终止后也会被init进程回收,
    29     // 不会成为僵尸进程。
    30     exit(0);
    31 }

    说明

           1. fork创建子进程以后,子进程拥有的是父进程的一个资源副本,而不是和它共享资源。

           2. 子进程终止后变成僵尸进程并不是系统BUG,而是因为子进程终止后,其一些信息操作系统或者用户以后还可能会用到。

  • 相关阅读:
    程序员高效学习
    红黑树(平衡操作详解)
    【设计模式】JDK源码中用到的设计模式
    pymysql.err.InternalError: (1205, 'Lock wait timeout exceeded; try restarting transaction')错误处理
    UPC:ABS
    洛谷:P1182:数列分段`Section II`
    python:数据库连接操作入门
    2018百度之星资格赛:1002:子串查询
    Educational Codeforces Round 48 (Rated for Div. 2)——A. Death Note ##
    python:pip命令使用
  • 原文地址:https://www.cnblogs.com/muchen/p/6354573.html
Copyright © 2020-2023  润新知