为什么要进行进程等待
子进程是有父进程创建的,而且父进程要承担一个重要的任务---回收子进程的数据资源和数据结构,如果没有父进程进行回收,当子进程结束后,它就会称为僵尸进程,就会造成资源泄露。
还有子进程运行的结果要由父进程进行获取,结果对还是不对,是否异常退出等
父进程通过进程等待的方式,回收子进程的资源,获取子进程退出信息。
wait()
#include<sys/wait.h>
pid_t wait(int*status);
这个函数如果成功等待那就返回等待进程的pid,否则返回-1
一个例子
#include<iostream>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<cstdlib>
using namespace std;
int main()
{
pid_t id=fork();
if(id==0)
{
int cnt=5;
while(cnt--)
{
cout<<"子进程的id"<<getpid()<<"父进程的id"<<getppid()<<endl;
sleep(1);
}
exit(0);
}
pid_t ret=wait(NULL);
if(ret>0)
cout<<"父进程等待成功"<<ret<<endl;
}
waitpid()
pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
status
这里重点讲一下status参数
对于子进程要么运行成功正常终止,要么遭遇异常被信号所杀,status是一个输出型参数由操作系统所填充,如果传递空,那么意味着表示不关心子进程的退出状态信息。父进程等待子进程一个重要的作用就是要知道子进程的退出信息,status就是让父进程获取退出信息的。status是一个位图
也就是说退出码就是status右移8位再和0xff按位与得到的。
#include<iostream>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<cstdlib>
using namespace std;
int main()
{
pid_t id=fork();
if(id==0)
{
int cnt=5;
while(cnt--)
{
cout<<"子进程的id"<<getpid()<<"父进程的id"<<getppid()<<endl;
sleep(1);
}
exit(10);
}
cout<<"父进程开始等待"<<endl;
//pid_t ret=wait(NULL);
int status=0;
pid_t ret=waitpid(id,&status,0);
if(ret>0)
{
cout<<"父进程等待成功"<<ret<<endl;
int exit_code=(status>>8)&0xff;
cout<<"status exit code"<<exit_code<<endl;
}
else
{
cout<<"父进程等待失败"<<endl;
}
}
可以看到这里的退出码正是10
options
这里还有另外一个参数这里的options实际上是进程等待方式,我前面写的代码的options是0,表示最常见的阻塞等待。阻塞等待就是单纯的等,不做其他的任何行动。 参数options提供了一些额外的选项来控制waitpid,参数 option 可以为 0 或可以用"|"运算符把它们连接起来使用,比如:
ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);
如果我们不想使用它们,也可以把options设为0,如:
ret=waitpid(-1,NULL,0);
WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。
示例
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid < 0){
printf("%s fork error\n",__FUNCTION__);
return 1;
}else if( pid == 0 ){ //child
printf("child is run, pid is : %d\n",getpid());
sleep(5);
exit(1);
} else{
int status = 0;
pid_t ret = 0;
do
{
ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待
if( ret == 0 ){
printf("child is running\n");
}
sleep(1);
}while(ret == 0);
if( WIFEXITED(status) && ret == pid ){
printf("wait child 5s success, child return code is :%d.\n",WEXITSTATUS(status));
}else{
printf("wait child failed, return.\n");
return 1;
}
}
return 0;
}
深入理解
用户将status传入给父进程,父进程在内核当中,然后父进程获取子进程的退出码和退出信号