等待子进程状态改变函数wait
函数原型:pid_t wait(int *status);
头文件:#include <sys/types.h> #include <sys/wait.h>
输入参数:
status: int型指针,用于获取子进程状态发生改变时,返回的状态值。
返回值:pid_t是一个宏定义,其实质是int被定义在#include <sys/types.h>
函数说明
调用wait函数将会使当前进程处于阻塞状态,直到有一个子进程的状态发生改变,当子进程接收到某个信号停止运行或者从stop状态转为继续执行时,被认为子进程的状态发生改变。
在子进程停止运行的状态下,执行wait函数将会使系统释放与子进程相关联的系统资源,如果不执行该函数,则子进程将会处于“僵停”状态,成为僵尸进程。
如果子进程的状态已经发生了改变(比如子进程已经停止运行)。调用wait函数将会立即返回。
如果函数执行成功返回进程PID,如果函数执行失败,则返回-1
等待指定子进程状态改变函数waitpid
函数原型:pid_t wait(pid_t pid,int *status,int options);
头文件:#include <sys/types.h> #include <sys/wait.h>
输入参数:
pid: 指定的子进程pid
status: int型指针,用于获取子进程状态发生改变时,返回的状态值。
options: 选项,
返回值:pid_t是一个宏定义,其实质是int被定义在#include <sys/types.h>
函数说明
waitpid函数的调用将阻塞调用进程的执行,直到pid参数指定的子进程状态发生了改变,默认情况下,waitpid只等待子进程的终止,但是这个行为可以通过options参数进行修改。
参数pid如何指定特定的进程或进程的集合
参数pid本质上是int型参数,其值可以分为四类表示,具体描述如下:
-
pid值小于-1,表示等待pid的绝对值与该参数相等的进程的所有子进程状态发生改变,比如传入的pid = -100 则调用该函数,系统所有pid值为100的进程的子进程状态发生改变,都会导致函数返回,停止阻塞。
-
pid值等于-1,表示等待当前进程的所有子进程状态发生改变。
-
pid值等于0,表示等待和调用该函数的进程拥有同一个进程组ID的进程状态发生改变(比如拥有同一个父进程的进程)。
-
pid值大于0,表示表示指定的进程的pid。
参数options的使用
参数options的值可以通过以下几个常量的值进行或运算取得,其字段名称以及具体含义如下:
- WNOHANG: 通知内核在没有已终止进程项时不要阻塞。即如果没有子进程已经终止,则立即返回。
- WUNTRACED:若实现支持作业控制,而pid指定的任一子进程已经暂停,且其状态尚未报告,则返回其状态。
- WCONTINUED:如果进程从stop状态变为继续执行状态时,返回该状态。
如果waitpid函数执行成功,返回状态发生改变的进程PID,如果WNOHANG被设置,并且同时有多个进程已经退出了,返回0,如果函数执行失败返回-1
错误类型
wait函数和waitpid函数错误状态保持一致,其错误信息由status字段获取。函数执行失败的错误类型的具体表述如下:
- ECHILD:对于wait函数返回该错误,表示当前没有任何未被释放的子进程。对于waitpid函数返回该错误,表示通过pid参数指定的进程不存在,或者该pid是当前调用进程的PID。
- EINTR:当前没有设置WNOHANG状态,并且在函数执行过程中捕获到了SIGCHILD信号或者是其他不被阻塞的信号。
- EINVAL:选项字段设置的状态无效。
官方例程
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}