一 相关知识:
1 ——僵尸进程:
(1)僵尸进程:
@ 僵死状态是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程;
@ 僵尸进程会以终止状态保持在进程表中,并且会在一直等待父进程读取退出状态代码;
@ 只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入僵尸状态。
(2)僵尸进程危害:
@ 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了;可父进程如果一直不读取,那个进程就一直处于Z(僵尸)状态;
@ 维护推出状态本身就是要用数据维护,也属于进程基本信息,所以保存在tast_struct(PCB)中,也就是说,Z状态一直不退出,PCB一直都要维护;
@ 那一个父进程创建了很多子进程,就是不回收,就会造成内存资源的浪费;因为数据结构对象本身就要占用内存;
(3)僵尸进程的避免
# 父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。
# 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后, 父进程会 收到该信号,可以在handler中调用wait回收。
# 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD,SIG_IGN) 通知内核,自己 对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号。
# 还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一 个孙进程 后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。
————————————————————————————————————
2 ——孤儿进程
@ 父进程如果提前退出,那么子进程就称之为“孤儿进程”;
@ 孤儿进程被1号init进程领养,当然要有init进程回收。
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害
**
二 模拟代码:
**
1 僵尸进程
makefile文件:
jiangshi:jiangshi.c
gcc jiangshi.c -o jiangshi
.PHONY:clean
clean:
rm -f jiangshi
jiangshi.c文件
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id > 0) //father
{
printf("father pid is %d\n",getpid());
sleep(10);
}
else //child
{
printf("child pid is %d\n",getpid());
sleep(3);
exit(EXIT_SUCCESS);
}
return 0;
}
结果:
————————————————————————————————————
2 孤儿进程
makefile文件
guer:guer.c
gcc guer.c -o guer
.PHONY:clean
clean:
rm -f guer
guer.c文件
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t id = fork();
if(id == -1)
{
perror("fork");
}
else if(id == 0) //child
{
printf("I am child,pid: %d,father pid is %d\n",getpid(),getppid());
sleep(5);
}
else //father
{
printf("I am father,pid: %d,child pid is %d\n",getpid(),getppid());
sleep(3);
exit(0);
}
return 0;
}
结果: