1、wait函数
当一个进程结束时,会关闭所有的文件描述符,释放所有的内存空间,但依然保存其PCB,内核在PCB中保存着一些信息。
如果是正常退出,则会保存退出状态。
如果是异常终止,则保存是哪个信号终止了该进程。
父进程通过调用wait()或者waitpid()函数,来获取这些信息,之后彻底清除改进程。
只有失败返回值 -1 .
父进程调用wait函数可以回收子进程终止信息,该函数有三个功能:
① 阻塞等待子进程的退出
② 回收子进程的残留资源
③ 获取子进程的结束状态(退出原因)
当一个进程终止是,操作的系统的隐式回收机制会
①关闭所有文件描述符
②释放用户空间分配的内存,pCB仍然存在,并保存改进程的退出状态
wait 使用传出参数的status来保存今后才能退出的状态,进一步借用宏函数判断进程终止的原因。可分为如下三组
-
WIFEXITED(status) 为非0 → 进程正常结束 WEXITSTATUS(status) 如上宏为真, 使用此宏 → 获取进程退出状态 (exit的参数)
-
WIFSIGNALED(status) 为非0 → 进程异常终止 WTERMSIG(status) 如上宏为真, 使用此宏 → 取得使进程终止的那个信号的编号。
-
WIFSTOPPED(status) 为非0 → 进程处于暂停状态 WSTOPSIG(status) 如上宏为真, 使用此宏 → 取得使进程暂停的那个信号的编号。 WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main(){
pid_t pid,wpid;
int status;
pid = fork();
if(pid==0){
printf("child,my parent=%d,going to sleep 10s\n",getppid());
//execl("abnormal","abnormal",NULL);
sleep(60);
printf("----------------child die---------------------\n");
exit(76);
}
else if(pid>0){
wpid =wait(&status);
if(wpid==-1){
perror("wait error");
exit(1);
}
}
if(WIFEXITED(status)){
printf("child exit with %d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status)){
printf("child killed by %d\n",WTERMSIG(status));
}
while(1){
printf("I an parent,pid=%d,myson = %d\n",getpid(),pid);
sleep(1);
}
}
2、waitpid函数
作用等于wait,但是可以指定pid,也可以不阻塞。
pid_t waitpid(pid_t pid, int *status, int options);
第一个参数----->指定想要回收的进程 pid
大于 0 回收指定ID的子进程
-1 回收任意子进程(相当于wait)
0 回收和当前调用waitpid一个组的所有子进程 < -1 回收指定进程组内的任意子进程
第二个参数----->传出的参数
第三个参数------>选择阻塞和不阻塞,设置为WNOHANG,且子进程正在运行,为非阻塞。
返回值:
成功:清理进程的pid
失败: 返回-1
注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。
示例:使用waitpid清理,指定pid的进程
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
int main(int argc,char * argv[] ){
int n=5,i;//默认创建5个进程
pid_t p,q,wpid;
for(i=0;i<n;i++){//父进程的出口
p=fork();
if(p==0){
break; //子进程的出口
}else if(i==2){
q=p;//得到第三个孩子的pid
}
}
if(n==i){
sleep(n);
printf("I am parent,pid = %d ,gid=%d \n",getpid(),getgid());
//① 清理所有的子进程,使用wait
//while(wait(NULL));
//② 回收第三个孩子,清理指定pid,使用waitpid
waitpid(q,NULL,0);//阻塞
printf("第三个孩子回收完毕!\n");
while(1);
//③ 清理所有的子进程 ,第一个参数-1,
/*
do {
wpid=waitpid(-1,NULL,WNOHANG);
if(wpid > 0){
n--
}
sleep(1);
}while(n>0)
*/
}else{
sleep(i);
printf("I am %dth child,pid = %d,gpid=%d\n",i+1,getpid(),getgid());
}
return 0;
}
ps -aux