回收子进程
1.一些概念:
孤儿进程
父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为进程领养孤儿进程。
僵尸进程
进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。
僵尸进程不能使用kill命令清除,因为kill命令只是用来终止进程的,而僵尸进程已经终止了。
2.wait函数
一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息,如果是正常终止则保存着退出状态;如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态可以在Shell中用特殊变量$?查看,当它终止时Shell调用wait或waitpid得到它的退出状态,同时清除这个进程。
父进程调用wait函数可以回收子进程终止信息。该函数有三个作用:
①阻塞等待子进程退出
②回收子进程残留资源
③获取子进程结束状态(退出原因);
pid_t wait(int *status);成功:清除掉子进程ID;失败:-1(没有子进程信息)
当进程终止时,操作系统的隐式回收机制会:1.关闭所有文件描述符;2.释放用户空间分配的内存。内核的PCB仍存在,其中保存该进程的退出状态。(正常终止 -> 退出值,异常终止 -> 终止信号)
可使用wait函数传出参数status来保存进程的退出状态,借助宏函数来进一步判断终止进程的具体原因,宏函数可分如下三组:
1.WIFEXITED(status)为非0 -> 进程正常结束
WEXITSTATUS(status)如上宏为真,使用此宏 -> 获取进程退出状态(exit参数或return返回值)
2.WIFSIGNALED(status)为非0 -> 进程异常结束
WTERMSIG(status)如上宏为真,使用此宏 -> 获取使进程终止的那个信号的编号
3.WIFSTOPPED(status)为非0 -> 进程处于暂停状态
WSTOPSIG(status)如上宏为真,使用此宏 -> 获取使进程暂停的那个信号的编号
WIFCONTINUE(status)为真 -> 进程暂停后已经进行运行
例:子进程正常退出,调用算上述宏函数
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/wait.h> 7 8 int main() 9 { 10 int pid = fork(); 11 int status; 12 int wpid; 13 if(pid == 0){ 14 sleep(3); 15 printf("----------------child process is over--------------\n"); 16 exit(100); 17 }else if(pid > 0){ 18 wpid = wait(&status); 19 printf("wpid = %d\n",wpid); 20 if(WIFEXITED(status)){ 21 printf("子进程正常退出,退出值为:%d\n",WEXITSTATUS(status)); 22 } 23 } 24 return 0; 25 }
运行结果:

3.waitpid函数
作用与wait相同,但waitpid可指定pid进程清理,可以不阻塞。
pid_t waitpid(pid_t pid,int *status,int options);成功:返回清理掉的子进程的id;失败:-1(无子进程)
特殊参数和返回情况:
参数pid:
>0 回收指定id的子进程
-1 回收任意子进程(相当于wait)
0 回收和当前调用waitpid一个组的所有子进程
<-1 回收指定进程组内的任意子进程
参数options:
0 阻塞,相当于wait
WNOHANG 非阻塞回收(轮询)
返回0:options传WNOHANG,且子进程正在运行
注意:一次wait或waitpid调用只能清理一个子进程;清理多个子进程应使用循环。
根据子进程id进行回收
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/wait.h>
7
8 int main()
9 {
10 int status;
11 int child_pid;
12 pid_t p,q;
13
14 int i;
15 int n = 5; //创建5个子进程
16 for(i=0;i<n;i++){
17 p = fork();
18 if(p == 0){
19 break; //子进程创建后退出循环
20 }else if(i == 3){
21 q = p; //取出第4个子进程的id
22 }
23 }
24
25 if(i == n){
26 sleep(n);
27 child_pid = waitpid(q,&status,0); //根据子进程id进行回收
28 while(1);
29 }else if(i<n){
30 sleep(i);
31 printf("I'm %d child,pid = %d,ppid = %d\n",i+1,getpid(),getppid());
32 }
33
34 return 0;
35 }
循环回收子进程
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/wait.h> 7 8 int main() 9 { 10 int status; 11 int child_pid; 12 pid_t p,q; 13 14 int i; 15 int n = 5; //创建5个子进程 16 for(i=0;i<n;i++){ 17 p = fork(); 18 if(p == 0){ 19 break; //子进程创建后退出循环 20 }else if(i == 3){ 21 q = p; //取出第4个子进程的id 22 } 23 } 24 25 if(i == n){ 26 sleep(n); 27 while(waitpid(-1,&status,0)!=-1){ //循环回收子进程 28 } 29 while(1){} //让父进程不退出 30 }else if(i<n){ 31 sleep(i); 32 printf("I'm %d child,pid = %d,ppid = %d\n",i+1,getpid(),getppid()); 33 } 34 35 return 0; 36 } 37 ~
非阻塞(轮询)方式回收子进程
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/wait.h> 7 8 int main() 9 { 10 int status; 11 int child_pid; 12 pid_t p,q; 13 14 int i; 15 int n = 5; //创建5个子进程 16 for(i=0;i<n;i++){ 17 p = fork(); 18 if(p == 0){ 19 break; //子进程创建后退出循环 20 }else if(i == 3){ 21 q = p; //取出第4个子进程的id 22 } 23 } 24 25 if(i == n){ 26 // sleep(n); 27 do{ 28 child_pid = waitpid(-1,&status,WNOHANG); 29 if(child_pid > 0){ //n>0代表回收成功 30 n--; 31 } 32 }while(n>0); 33 }else if(i<n){ 34 sleep(i); 35 printf("I'm %d child,pid = %d,ppid = %d\n",i+1,getpid(),getppid()); 36 } 37 38 return 0; 39 } 40 ~

浙公网安备 33010602011771号