1.函数原型
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
2.wait函数
wait函数会一直处于阻塞状态,直到有一个子进程退出,并返回退出子进程的ID,存储返回状态到wstatus中。
调用成功返回子进程的进程id。
3.waitpid函数
waitpid函数可以指定需要等待退出的子进程ID,wait函数等价于waitpid(-1, &wstatus, 0);调用成功返回子进程的进程id。
waitpid各项参数的含义如下:
pid
- 小于-1 等待所有组ID等于pid的子进程;
- 等于-1 等待父进程创建的任何子进程;
- 等于0 等待所有组id等于父进程组id的子进程;
- 大于0,参数pid表示需要等待的子进程的ID;
options通常为0表示等待进程终止,也可以是以下宏
- WNOHANG 如果没有子进程存在,立即返回,结束阻塞状态;
- WCONTINUED 如果子进程在停止状态接收到了SIGCONT信号重新恢复运行,waitpid函数也立即返回;
- WUNTRACED
4.waitid函数
waitid提供了更加丰富的选项,使用waitid可以实现wait和waitpid的所有功能,该函数调用成功返回0,并且会将子进程的信息存储在infop中,具体的参数如下:
idtype
- P_PID 等待进程ID等于id的进程终止;
- P_GID 等待任何进程组ID等于id的子进程终止
- P_ALL 等待任何子进程的终止,只要有一个进程终止函数就会返回,这个时候第二个参数id无效;
如果infop不为NULL,则档waitid成功返回时,这个结构将会被填写,我们可以从该结构中获取我们感兴趣的信息,其中有:
- si_pid: 子进程的进程id;
- si_uid:子进程的真实用户id;
- si_signo:总是设置为SIGCHID;
- si_status:可以是子进程的退出状态,或者是造成子进程状态改变的原因,si_code用来解释这个字段;
- si_code:可以是CLD_EXITED、CLD_KILLED、CLD_DUMPED、CLD_TRAPPED、CLD_CONTINUED,记录子进程状态改变的原因;
options
- WEXITED 等待子进程被终止;
- WSTOPPED 等待子进程停止,stoped状态可以恢复运行;
- WCONTINUED 等待子进程从stoped状态恢复;
- WNOHANG 如果没有子进程立即返回;
- WNOWAIT 使子进程处于可等待状态,后续可以调用wait获取子进程的状态信息;
5.关于wait、waitpid、waitid接收子进程的返回值
- wait和waitpid接收到的子进程的返回值存储在status中,waitid函数接收到的返回值存储在infop结构体的si_status中;
- 这三个函数得到status的值之后直接使用printf打印出来,得到的结果与子进程实际return的值不同,需要使用WIFEXITED、WIFSIGNALED、WIFSTOPPED进一步解析,可以直接使用man waitpid在ubuntu下查看详细信息;
5、示例代码
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
/*在main函数中创建3个进程,分别使用wait、waitpid、waitid等待子进程退出*/
void check_exit_status(int status)
{
if(WIFEXITED(status))//如果子进程退出,使用WEXITSTATUS获取子进程的return值
{
printf("子进程返回信息码:%d\n",WEXITSTATUS(status));
}else if(WIFSIGNALED(status))//如果子进程被信号打断,使用WTERMSIG获得对应信号的值
{
printf("子进程信号中断返回信息码:%d\n",WTERMSIG(status));
}else if(WIFSTOPPED(status))//如果子进程被停止,使用WSTOPSIG获得对应的信号的值
{
printf("子进程暂停返回信息码:%d\n",WSTOPSIG(status));
}else
{
printf("其他退出信息!\n");
}
}
int value = 0;
int main(int argc,char *argv[])
{
int ret = -1;
int status;
siginfo_t info;
pid_t pid = 0;
pid_t pid1 = 0;
pid_t pid2 = 0;
pid_t pid3 = 0;
pid1 = fork();
if(pid1 == 0)
{
sleep(1);
while(1)
{
printf("child1 process pid %u,value=%d\r\n",getpid(),value);
value++;
//sleep(1);
if(value == 5)break;
}
//exit(3);
return 3;
}
else
{
pid2 = fork();
if(pid2 == 0)
{
sleep(2);
while(1)
{
printf("child2 process pid %u,value=%d\r\n",getpid(),value);
value++;
//sleep(1);
if(value == 5)break;
}
//exit(4);
return 4;
}
else
{
pid3 = fork();
if(pid3 == 0)
{
sleep(3);
while(1)
{
printf("child3 process pid %u,value=%d\r\n",getpid(),value);
value++;
//sleep(1);
if(value == 5)break;
}
//exit(5);
return 5;
}
else
{
printf("waiting for child progress exit!\r\n");
//指定等待进程2退出
pid = waitpid(pid2,&status,0);
printf("child %u exit\r\n",pid,status);
check_exit_status(status);
//只要有一个进程终止就会解除阻塞
ret = waitid(P_ALL,0,&info,WEXITED);
if(0 == ret)
printf("child %u exit,status = %d,code = %d\r\n",info.si_pid,info.si_status,info.si_code);
check_exit_status(info.si_status);
//任何进程退出都会解除wait阻塞
pid = wait(&status);
printf("child %u exit,status = %d\r\n",pid,status);
check_exit_status(status);
}
}
}
}
运行结果: