wait和waitpid函数
无论进程是正常结束还是非正常结束,内核都会发送SIGCHLD信号给它的父进程,以告知子进程结束。因为子进程结束是一个异步事件,它可以发生在任何父进程运行的时间,这个信号也是由内核异步通知父进程的。父进程可以选择忽略这个信号或者提供一个被称作“信号句柄”的函数来处理。默认处理方法是忽略该信号。现在聊这个还有点早,现在只要知道wait或waitpid可以:
- 如果它的所有子进程都在运行,那么会阻塞。
- 如果一个子进程已经结束并且正在等待反馈自己的终止状态,立即返回一个子进程的终止状态。
- 如果没有任何子进程在运行,那么会立即返回一个错误。
如果进程调用了wait是因为它收到了SIGCHLE信号的话,我们希望wait可以立即返回。但是如果在随机的时间点调用它的话,它会产生阻塞。
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
|
Both return: process ID if OK, 0 (see later), or 1 on error |
这两个函数的不同是:
- wait函数可以阻塞调用者,直到子进程结束。而waitpid有一个防止调用者阻塞的选项。
- waitpid函数并不是先等待子进程结束;它有很多的选项用于控制哪些进程是它要等待的。
如果一个子进程已经终止并且变成了zombie进程,wait会立即返回子进程的状态。另外它阻塞了调用者直到子进程结束。如果调用者有多个子进程,当其中一个结束时wait就会返回。因为进程ID被程序返回,所以可以一直得知是哪个子进程结束了。
这两个函数的statloc是一个指向整数的指针,用于存储进程的终止状态。如果并不关心终止状态,只要传一个空指针给这个参数就可以。
传统上,这两个函数返回的整数状态是被实现定义的,一些位指示了退出状态(正常退出),另一些位指示了信号数(非正常返回),有一位用来指示是否产生了core file,等等。POSIX.1指定了终止状态,这些状态使用定义在<sys/wait.h>中的各种宏来辨别。四种互斥的宏告诉我们进程是如何终止的,并且它们都以WIF开头。基于这四种宏哪个一为真,就可以使用其它一些宏来获得退出状态和信号量等等。
下面是这四种宏:
Figure 8.4 Macros to examine the termination status returned by wait and waitpid
|
如果有很多的子进程,我们只想得到某个特定的子进程的终止状态,在一些版本的unix系统中的做法是,wait收到一个消息后判断它的PID是不是我们需要的,如果不是,再次运行wait(因为wait只要任何一个子进程结束,它就会返回)。从实用角度出发,POSIX.1定义了waitpid函数。
对于waitpid的pid参数说明:
pid==1 等同于wait函数
pid>0 等待特定的PID子进程。
pid==0 等待子进程的组ID等同于调用进程的ID(这说的是不是调用waitpid的进程?)。
pid<1 等待子进程的组ID等于pid的绝对值。
waitpid函数返回子进程的ID,它的终止状态存储在内存中被statloc指针索引。wait函数唯一会发生的实际错误是,调用它的进程没有子进程(另一种可能是函数的调用被信号中断)。同样的错误也可能发生在waitpid函数上,如,指定的进程ID或进程组ID不存在,或者没有子进程。
option参数可以让waitpid有更多的控制方式,这个参数可以是0或者是一些常量做OR运算,可以使用的常量如下:
|
waitpid函数提供三种功能,但是并不提供给wait函数。
- waitpid函数让我们等待特定的进程,而wait函数返回任意已终止的子进程的状态。
- waitpid函数提供了一个非阻塞版本wait。当我们想得到子进程的状态,但是我们不想阻塞程序时。
- waitpid函数支持任务控制,可以使用WUNTRACED和WCONTINUED选项。