两种特殊的进程---孤儿进程和僵尸进程

一.两种进程的简要介绍:

     孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为 init 进程,称为 init 进程领养孤儿进程 ;

     僵尸进程:进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核之中,变成僵尸进程(它几乎放弃进程退出前占用的所有内存,既没有可执行代码,也不能被调度,只在进程列表中保留一个位置,记载进程的退出状态,供父进程收集);


二.实例

 1.孤儿进程代码及结果如下:

#include"stdio.h"
#include"stdlib.h"
#include"unistd.h"

int main(){

        pid_t pid;
        printf("Begin...\n");
        pid = fork();

        if(pid == -1){    // pid 值为-1,则创建子进程失败
                perror("fork error!");
                exit(1);
        }
        else if(pid == 0){    // pid 值为0,则创建子进程成功

                printf("i am child,pid = %u,ppid = %u\n",getpid(),getppid());
                sleep(3);
                printf("i am child,pid = %u,ppid = %u\n",getpid(),getppid());
        }
        else{    // pid 值为非负整数,则为父进程
                printf("i am parent,pid = %u,ppid = %u\n",getpid(),getppid());
                sleep(1);
                printf("...parent goes to die...");
        }

        return 0;
}

  由结果截图可知,子进程的 ppid 在父进程去世之后发生了改变,输入以下代码查看该 id 的进程:

ps xua | grep 1393

注: 对子进程领养的进程称为 init 进程,但是不同版本的 init 是有所不同的,本人是在 systemd下

        ,所以,如果出现的 id 不是 1 ,也是正确的。


2.僵尸进程代码及结果如下:

#include"stdio.h"
#include"stdlib.h"
#include"unistd.h"

int main(){

        pid_t pid;
        printf("Begin...\n");
        pid = fork();

        if(pid == -1){    // pid 值为-1,则创建子进程失败
                perror("fork error!");
                exit(1);
        }
        else if(pid == 0){    // pid 值为0,则创建子进程成功

                printf("i am child,pid = %u,ppid = %u\n",getpid(),getppid());
                sleep(3);
                printf("child goes to die...\n");
        }
        else{    // pid 值为非负整数,则为父进程
                int i;
                for(i=1;i<1000;i++){
                        printf("i am parent,pid = %u,ppid = %u\n",getpid(),getppid());
                        sleep(1);
                }
        }

        return 0;
}

在执行代码的过程中,开启另一个终端(terminal),并输入以下命令:

ps xua

 由结果可知:

 (1)第一个terminal中父进程仍在不断输出,并未对子进程进行回收;

 (2)第二个terminal中输入命令,可以看到 [a.out] <defunct> ,说明其为僵尸进程;


思考:僵尸进程是不能使用 kill 命令清除掉的,因为 kill 仅可终止进程,而僵尸进程已经终止,那应该怎么办呢???

      当僵尸进程的父进程被终止后,僵尸进程将作为孤儿进程被 init 进程接收,init 进程会不断调用

wait() 函数获取子进程状态,对已处于僵尸态的进程进行处理。

因此我们可以理解,为什么我们在查看僵尸态进程时要开启另一个 terminal,如果在原 terminal 查看,势必使用 Ctrl+C,这样会将父进程杀死,僵尸进程也被处理,查看不到僵尸进程的相应信息


注:

1.处于僵尸态的进程不能再次被运行,但是却会占用一定的内存空间,并占据进程编号,当系统中的僵尸进程较多时,将会消耗系统的大部分内存,新的进程可能因内存不足或无法获取 pid 而无法创建,因此应尽量避免僵尸进程的产生---在父进程中通过 wait() 和 waitpid() 函数可以有效防止僵尸进程的产生;

2.孤儿进程永远不会成为僵尸进程。


参考资料:

1.linux全套教程【黑马】_哔哩哔哩_bilibili


写在最后:

       该博客是本人学习的一些总结,如果各位有不同见解,可以评论提出或者与我联系改正,谢谢大家!!!