两种特殊的进程---孤儿进程和僵尸进程
一.两种进程的简要介绍:
孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为 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.孤儿进程永远不会成为僵尸进程。
参考资料:
写在最后:
该博客是本人学习的一些总结,如果各位有不同见解,可以评论提出或者与我联系改正,谢谢大家!!!