一 、僵尸进程
1. 我们知道进程状态有:R运行状态,S睡眠状态(可中断睡眠状态),D磁盘休眠状态(不可中断睡眠状态),T停止状态,X死亡状态。还有一种比较特殊的就是僵尸状态(Z)了。
2. Z(zombie)--僵尸进程
<1>当子进程退出,父进程无法读取到子进程退出的返回码时就会产生僵尸进程。父进程还在运行,子进程进入僵尸状态。
<2>僵尸进程以进程中止的状态保持在进程表中,并且一直会等待父进程读取退出状态代码。
下面我们来实现一个简单的僵尸进程:
test.c代码部分:
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 int main()
5 {
6 pid_t id=fork();
7 if(id < 0){
8 //error
9 perror("fork");
10 return 1;
11 }
12 else if( id == 0 ){//child
13 printf("child[%d] is begin Z!!!\n",getpid());
14 sleep(5);
15 exit(EXIT_SUCCESS);
16 }
17 else{//parent
18 printf("parent[%d] is sleeping!!!\n",getpid());
19 sleep(30);
20 }
21
22 return 0;
23 }
makefile:
1 test:test.c
2 gcc -o test test.c
3
4 .PHONY:clean
5 clean:
6 rm -f test
在此终端下编译代码:
编译时在另一个终端启动监控:
我们可以看到 ,子进程在睡眠后退出,由于父进程不读取其退出状态,子进程进入Z状态。
3.僵尸进程的危害
<1>我们知道,父进程创建出子进程,是想让子进程完成某项工作,那么子进程退出时就要告诉父进程,你交给我的工作,我完成的如何。可是如果父进程一直不读取子进程的退出状态,那么子进程就会一直处于Z状态。因此,进程的退出状态必须被维持下去。
维护进程的退出状态本质上是要用数据维护,这个数据也属于进程信息,因此数据会保存在PCB中。如果Z状态一直不退出,那么PCB就要一直维护进程的退出状态。
如果一个进程创建出很多子进程,但它就是不读取子进程的退出状态,那么由于PCB占用内存,只开辟空间而不回收就会造成内存资源的浪费,进而造成内存泄漏。因此,父进程要及时回收子进程,避免内存泄漏,对系统造成威胁。
二、 孤儿进程
1.父进程先退出,子进程就被称为“孤儿进程”。
父进程退出后,子进程被1号进程init领养,init进程对孤儿进程完成状态收集工作。
实现:
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4
5 int main()
6 {
7 pid_t id =fork();
8 if(id < 0){
9 perror("fork");
10 exit(0);
11 }
12 else if(id > 0){//parent
13 printf("I am parent,pid:%d\n",getpid());
14 sleep(5);
15 exit(0);
16 }
17 else{//child
18 printf("I am child,pid:%d\n",getpid());
19 sleep(10);
20 exit(0);
21 }
22 return 0;
23 }
编译并且在另一个终端启动监控:
可以看出,当父进程退出后,子进程的ppid变为了1,这样,当一个孤儿进程结束了其生命周期的时候,init进程就会处理它的一切善后工作,因此一般来说,孤儿进程不会有什么危害。