1.僵死进程产生的原因或者条件:
当子进程先于父进程结束,父进程没有获取子进程的退出码,此时子进程变成僵死进程;(即就是子进程结束了,但父进程还没有结束的时候才会出现僵死进程)
(代码中 ,子先于父)(& 后台运行)
当一个进程结束的时候,只有进程的退出码被父进程获取后,父进程才能退出,进程的PCB才会被释放,否则父进程会一直等待退出码,在得到退出码之前,这个进程就是一个僵死进程。
2.演示僵死进程:
vim fork.c
#include<stdlib.h>
#include<wait.h>
int main()
{
char *s=NULL;
int n=0;//控制父子进程的次数
pid_t id=fork();
assert(id!=-1);
if(id==0)//子进程
{
s="child";
n=7;
}
else
{
s="parent";
n=3;
int val=0;
if(WIFEXITED(val))//如果正常退出
{
printf("val=%d\n",WEXITSTATUS(val));
}
wait(&val);
printf("val=%d\n",val);
}
//父子进程一起运行
int i=0;
for(;i<n;i++)
{
printf("s=%s ,pid=%d ,ppid=%d n的地址=%p n=%d\n",s,getpid(),getppid(),&n,n);
sleep(1);
}
exit(0);
}
3.僵死进程带来的影响
(1)进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎 么样了。可父进程如果一直不读取,那子进程就一直处于Z状态。
(2)维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话 说,Z状态一直不退出,PCB一直要维护
(3)那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?
答:是的。因为数据结构 对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空 间
(4)会造成内存泄漏
4.如何去处理僵死进程?
(1)父进程先结束
比如子进程的n改为7,父进程的n改为3;
(子进程会变成孤儿进程,孤儿进程会被收养,"父进程"就会获取退出码;(调用wait);
(红帽子是init(pid==1)收养孤儿进程,Unbuntu是操作系统指定了一个进程));
(2)父进程调用wait()方法获取子进程的退出码;
父进程执行7次,子进程改为3次;就能观察到僵死进程(放到后台运行&,ps);
#include<stdlib.h>
#include<wait.h>
int main()
{
char *s=NULL;
int n=0;//控制父子进程的次数
pid_t id=fork();
assert(id!=-1);
if(id==0)//子进程
{
s="child";
n=7;
}
else
{
s="parent";
n=3;
int val=0;
if(WIFEXITED(val))//如果正常退出
{
printf("val=%d\n",WEXITSTATUS(val));
}
wait(&val);
printf("val=%d\n",val);
}
//父子进程一起运行
int i=0;
for(;i<n;i++)
{
printf("s=%s ,pid=%d ,ppid=%d n的地址=%p n=%d\n",s,getpid(),getppid(),&n,n);
sleep(1);
}
exit(0);
}
处理僵死进程的方法一:
父进程执行3次,子进程改为7次;去观察僵死进程没有了;收养孤儿进程 的,一定会调用wait(就是获取退出码的);获取了退出码,操作系统就会把
pcb删掉,就不会出现僵死进程;
处理僵死进程的方法二:
父进程调用wait方法;
1命令, 2 系统调用 3 库函数
man 2 wait
else
{
s="parent";
n=7;
int val=0;
wait(&val);
printf("val=%d\n",val);
}
其实两种处理僵死进程的方法的本质是一样的,都调用了wait方法,获取退出码;
但是两种方法都有区别:就是父进程调用wait会阻塞,等子进程执行完之后,父进程才会去执行
1 #include <stdio.h>
2 #include<assert.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<stdlib.h>
6 #include<wait.h>
7
8 int main()
9 {
10 char *s=NULL;
11 int n=0;//控制父子进程的次数
12
13 pid_t id=fork();
14 assert(id!=-1);
15
16 if(id==0)//子进程
17 {
18 s="child";
19 n=3;
20 }
21 else
22 {
23 s="parent";
24 n=7;
25 int val=0;
26 wait(&val);
27 printf("val=%d\n",val);
28 }//获取退出码
29 //父子进程一起运行
30 int i=0;
31 for(;i<n;i++)
32 {
33 printf("s=%s ,pid=%d ,ppid=%d n的地址=%p n=%d\n",s,getpid(),getppid (),&n,n);
34 sleep(1);
35 }
36 exit(0);
37 }
5.子进程的退出码
改写码:exit(3)
执行显示val=768;
man 2 wait
WIFEXITED:正常退出的状态;
WEXITSTATUS:获取退出码;