前言
前面我们说明了进程等待的必要性,父进程通过进程等待,来回收子进程的资源,并且得知子进程的运行状态,下面我们接着谈谈wait和waitpid
我们先看看wait和waitpid的函数声明
#include <sys/types.h>/* 提供类型pid_t的定义*/
#include <wait.h>
int wait(int *status)
#include<sys/types.h>
#include<sys/wait.h>
定义函数 pid_t waitpid(pid_t pid,int * status,int options);
这两个函数有相似的功能,我们以waitpid来举例说明
waitpid一共有三个参数
第一参数pid,它通常有两种赋值方式,-1,和pid > 0
-1就是等待该进程的任意一个子进程
> 0就是等待特定的进程,这个特定的进程也就是我们所要填入的pid值
第二个参数是status,它是一个输出型参数,主要是用来获取子进程的状态信息
如果子进程是正常跑完了它的代码,那么它的退出码是有意义的
如果子进程遇到了崩溃等其它情况,使它的代码没有跑完,那么它的退出码就没有意义,这时我们要看它的退出信号
上一篇文章已经说明过一种获取进程退出码和退出信号的方法了
接下来我们再说明另一种更加优雅的方式获取进程状态信息
使用两个宏函数来解决
WIFEXITED(status)
这个是用来检测子进程是否正常退出的,如果为true证明子进程是正常退出的,反之就没有正常退出
另一个宏函数是
WEXITSTATUS(status)
这个宏是用来获取子进程的退出码的
第三个参数options它也有两种赋值方式,0和WNOHANG
它默认是0,0代表着父进程阻塞式的等待子进程
换句话说是父进程不能再执行其它代码直到等待子进程退出
在操作系统上说是父进程被操作系统从运行队列上换下,放到阻塞队列或者等待被操作系统调度
这种方法是十分的不好的,创建子进程就没有什么意义了
另一种赋值方式就是WNOHANG这种方法就十分的好
它会检测子进程的退出状态,如果返回的是子进程的pid证明子进程已经退出
返回值是0证明子进程没有退出,还在运行
返回值是-1证明出错了
根据上面的解释也就是说,如果waitpid填入的是WNOHANG父进程调用一次检测一次子进程的状态,所以我们要不停的检测直到子进程退出或者其它情况。
在下一次调用waitpid的间隙,我们可以让父进程进行其他任务
下面有一个小例子
#include <iostream>
#include <vector>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;
typedef void (*handler_t)();
std::vector<handler_t> handlers;
void func_one()
{
std::cout << "这是临时任务1" << std::endl;
}
void func_two()
{
std::cout << "这是临时任务2" << std::endl;
}
void Load()
{
handlers.push_back(func_one);
handlers.push_back(func_two);
}
int main()
{
pid_t id = fork();
if(id < 0)
{
perror("fork");
exit(1);
}
}
else if(id == 0)
{
int cnt = 5;
while(cnt--)
{
cout << "我是子进程" << cnt << getpid() << endl;
sleep(1);
}
}
else
{
int status = 0;
int quit = 0;
cout << "我是父进程" << endl;
while(!quit)
{
cout << "父进程等待子进程中" << endl;
pid_t res = waitpid(-1, &status, WNOHANG);
if(res > 0)
{
cout << "等待子进程成功" << endl;
cout << "子进程退出码为" << WEXITSTATUS(status) << endl;
quit = 1;
}
else if(res == 0)
{
cout << "子进程还在运行" << endl;
if(handlers.empty())
{
Load();
}
for(auto iter : handlers)
{
iter();
}
}
else
{
cout << "出错了" << endl;
quit = 1;
exit(1);
}
sleep(1);
}
}
return 0;
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了waitpid的使用。