首先我们来了解一下所谓的僵尸进程,
僵尸进程就是两个进程,一个父进程,一个子进程,其子进程终止后,0-3G的用户内存被回收,而3-4G的部分内存被回收,但是3-4G内存中的PCB等待父进程回收,若PCB未被父进程回收,我们称这个进程为僵尸进程,
注,之所以保留PCB,是因为其中保存着子进程的终止状态
父进程回收子进程的资源所用到的函数就是我们今天所要说的wait()和waitpid()函数
那么我们先来了解一下wait函数
wait是一个阻塞函数,如果没有可以回收的子进程,则为阻塞状态
如果无子进程,则返回-1
如果回收成功,则返回子进程的pid
返回值pid_t
wait() 只有一个参数 可以为NULL,也可以为int* status
所需要的头文件
#include<sys/type.h>
#include<sys/wait.h>
而waitpid()是对wait()函数的优化,我们在父进程使用wait()函数时,因为这个函数是处于阻塞状态的,使父进程不能处理其他事情,这样便浪费了父进程的资源,所以我们引出了waitpid()
waitpid()非阻塞 函数有三个参数
参数1:<-1时 回收组ID(该组可为用户指定)
-1 时 回收任意的相关进程
0 时,回收调用者组中的子进程
>0时,回收一个指定进程
参数2:可为NULL也可为int* status 为子进程的终止情况(退出码)
参数3:WNOHANG 为非阻塞状态
返回值 -1:失败或者没有回收子进程返回-1
>0: 返回回收的子进程ID
0:代表子进程未结束,非阻塞轮询返回
注:参数2为传出参数 使用宏函数 WIFEXITED(status)
WEXITSTATUS(status)
WIFSIGNALED(status)
WTERMSIG(status)
前两个宏函数为一组 ,后两个宏函数为一组,前两个是正常退出,后两个代表信号退出
下面我们来看一下代码:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <string.h> #include <sys/types.h> int main(void) { pid_t pid,wpid; int status,i;//子进程的终止 for(i=0;i<10;i++){ pid = fork(); if(pid == 0) break; } if(pid > 0){ printf("parent pid=%d\n",getpid()); //wait阻塞函数,如果没有可回收子进程阻塞,如果没有子进程返回-1,如果回收成功返回子进程pid //waipid return value:-1,>0,0 //-1:没有可回收子进程 //>0:返回回收子进程pid //0:代表子进程未结束,非阻塞轮询返回 while((wpid = waitpid(-1,&status,WNOHANG))!=-1){ if(wpid > 0) { if(WIFEXITED(status)) printf("parent wait child pid:%d\texit code:%d\n",wpid,WEXITSTATUS(status)); if(WIFSIGNALED(status)) printf("parent wait child pid:%d\tsignal No:%d\n",wpid,WTERMSIG(status)); } } }else if(pid == 0){ printf("child id=%d\tpid=%d\n",i,getpid()); if(i<9){ sleep(i); exit(i); } while(1); }else{ perror("Fork Call Failed:"); exit(0); } return 0; }