函数 waitpid 等待特定子进程

Linux 中,父进程可以通过函数 waitpid 来等待它的子进程终止或者停止
#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int *statusp, int option);参数 PID
- 第一个参数
pid > 0那么等待的进程是一个单独的子进程,子进程的进程值,也就是子进程的 id 就是这个 pid 参数的值 - 第一个参数
pid == -1表示等待的进程是所有子进程组成的集合
参数statusp
非空返回状态信息
- 第二个参数
statusp是非空的,那么函数waitpid就会在 status 中放上导致返回的子进程的状态信息
wait.h 的头文件中定义了解释 status 参数的几个宏
假如子进程是通过函数 exit 或者一个 return 正常终止,那么这个宏的解释结果就是 ture
wait函数等待所有子进程
wait 函数算是 waitpid 的语法糖(或许?)
int wait(int *statusp)
wait(&status) 等价于 waitpid(-1 ,&status ,0)
- 挂起当前进程的执行直到它的一个子进程终止
- 返回已终止子进程的 pid
- 如
child_status != NULL, 则在该指针指向的整型量表明子进程终止原因和退出状态信息:
用 wait.h 头文件中定义的宏函数来检查,例如:WIFEXITED (status)、 WEXITSTATUS (status)、
、WIFSIGNALED (status) 、 WTERMSIG (status) 、WIFSTOPPED (status) 、WSTOPSIG (status) 、WIFCONTINUED (status)
wait挂起当前进程直到子进程终止

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
int main() {
int child_status;
if (fork() == 0) {
printf("HC: hello from child\n");
exit(0);
} else {
printf("HP: hello from parent\n");
wait(&child_status); //挂起当前进程,在这里停住,直到子进程销毁,然后向下执行,有点像promise那个异步的意思
printf("CT: child has terminated\n");
}
printf("Bye\n");
}子进程的结束顺序是任意的
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
int main() {
int N = 50;
pid_t pid[N]; //开N个进程
int i, child_status;
for (i = 0; i < N; i++) //遍历每个进程
if ((pid[i] = fork()) == 0) { //存下当前子进程的pid
exit(100+i); /* Child 父进程跳过这一句*/
}
for (i = 0; i < N; i++) { /* Parent 父进程来这里*/
pid_t wpid = wait(&child_status); //等待所有子进程
if (WIFEXITED(child_status))
printf("Child %d terminated with exit status %d\n",
wpid, WEXITSTATUS(child_status)); //输出子进程的停止信息,WEXITSTATUS判定status是否合法为true
else
printf("Child %d terminate abnormally\n", wpid); //还会返回子进程的pid,报告是哪一个
}
}N 开大一点就会发现,进程的停止是随机的,没有固定顺序
示例

为了理解函数 waitpid 的用法,接下来我们看一个代码示例图中这段代码附近程,通过循环创建了 n 个子进程。根据之前所学过的知识,我们可以确定每个子进程都会执行函数 exit,因此每个子进程会以一个唯一的退出状态退出。接下来父进程调用 waitpid 作为 while 循环的测试条件,等待他所有的子进程终止。这里我们可以看到函数 waitpid 有三个参数
其中参数 - 1 表示父进程所等待的进程集合都是该父进程所创建的子进程
接下来检查子进程的退出状态。如果子进程是正常终止的,也就是说子进程是调用函数 exit 终止的。根据前面所讲到的这个宏的返回值就是 true,那么父进程就会将这个子进程的信息打印出来
这里需要注意的是,程序不会按照特定的顺序回收子进程。也就是说,当我们再次运行该程序时,两个子进程都可能以相反的顺序被回收
为了消除这种不确定性,我们对这段代码进行一下改进。改进后的代码可以按照父进程创建子进程的相同顺序来回收这些子进程,这里父进程用一个数组 pid[N] 来存储所有子进程的 PID,然后通过 PID 的值作为第一个参数来调用函数 waitpid,这样一来,父进程就可以按照创建子进程的顺序来等待每个子进程的结束。同样,我们还是根据宏的返回值来判断子进程是否正常退出。如果解释结果是 true,打印子进程的相关信息,否则输出非正常终止的信息