僵尸进程

子进程是父进程调用fork生成的,如果父进程在子进程之前结束,那么对于对应的父进程都已经结束的所有子进程,它们的父进程都会变成init进程,也就是这些子进程被init进程领养;在一个进程结束时,内核会逐个检查所有的活动进程,来判断它是否是正要结束的子进程,如果是,就会将该进程的父进程ID改为1,也就是init这个进程,如此就保证了每个进程都有一个父进程

如果子进程在父进程之前结束,子进程会将其结束状态返回给父进程;内核为每个结束的子进程保存了一定的信息,所以当子进程的父进程在调用wait或者waitpid的时候,是可以得到这些状态信息的,比如进程ID,结束状态等

进程终止后,内核会释放该进程所使用的所有存储区,关闭所有打开的文件,而一个已经终止但是其父进程尚未对其进行善后处理,也就是没有获取终止子进程的有关信息,释放它仍占用的资源,这样的一个已经终止的进程就是僵尸进程

前面的例子,父进程打印1次,而子进程打印3次,只需要将他们打印执行的次数交换一下,即父进程打印3次,子进程打印1次,并且不进行任何wait,在执行这个程序过程中,不停通过ps来查看进程,就会看到僵尸进程

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(){
    pid_t pid;
    char *message;
    int n;

    if ((pid = fork()) < 0) {
        printf("fork failed...\n");
        exit(1);
    } else if (pid == 0){
        message = "child now...";
        n = 1;
    } else {
        message = "parent now...";
        n = 3;
    }

    for(; n > 0; n--){
        puts(message);
        sleep(1);
    }
    return 0;
}

编译运行,与此同时执行ps命令:

$ ./a.exe
parent now...
child now...

$ ps aux
      PID    PPID    PGID     WINPID   TTY     UID    STIME COMMAND
     8244    3964    8244       4704  pty1    1000 14:09:50 /usr/bin/ps
     3964    4604    3964       5092  pty1    1000 12:03:03 /usr/bin/bash
     5048       1    5048       5048  ?       1000 11:42:52 /usr/bin/mintty
     6960    2216    2216       6960  pty0    1000 14:09:49 /home/lihui/a <defunct>
     2216    4372    2216       6432  pty0    1000 14:09:49 /home/lihui/a
     4372    5048    4372       4228  pty0    1000 11:42:52 /usr/bin/bash
     4604       1    4604       4604  ?       1000 12:03:03 /usr/bin/mintty

由于父进程并没有wait等函数,因此子进程结束之后变成了僵尸进程,在父进程还没有完全打印完的时候,可以看到一个defunct的进程,父进程此刻没有为其善后,可是过了一会儿,再用ps命令查看,僵尸进程没了,想要看更直观更明显效果的话,可以直接父进程里面来一个sleep N秒,这样僵尸进程就会一直存在,直到父进程苏醒

$ ./a.exe
parent now...
child now...
parent now...
parent now...

$ ps aux
      PID    PPID    PGID     WINPID   TTY     UID    STIME COMMAND
     3964    4604    3964       5092  pty1    1000 12:03:03 /usr/bin/bash
     5048       1    5048       5048  ?       1000 11:42:52 /usr/bin/mintty
I    4372    5048    4372       4228  pty0    1000 11:42:52 /usr/bin/bash
     7000    3964    7000       4772  pty1    1000 14:37:54 /usr/bin/ps
     4604       1    4604       4604  ?       1000 12:03:03 /usr/bin/mintty

但是由于父进程并没有添加wait和waitpid,因此父进程不会主动去回收子进程资源善后,我觉得是父进程结束之后,子进程被init收养,最终结束的~!

发表评论