wait和waitpid函数

wait和waitpid函数

无论进程是正常结束还是非正常结束,内核都会发送SIGCHLD信号给它的父进程,以告知子进程结束。因为子进程结束是一个异步事件,它可以发生在任何父进程运行的时间,这个信号也是由内核异步通知父进程的。父进程可以选择忽略这个信号或者提供一个被称作“信号句柄”的函数来处理。默认处理方法是忽略该信号。现在聊这个还有点早,现在只要知道waitwaitpid可以:

  • 如果它的所有子进程都在运行,那么会阻塞。
  • 如果一个子进程已经结束并且正在等待反馈自己的终止状态,立即返回一个子进程的终止状态。
  • 如果没有任何子进程在运行,那么会立即返回一个错误。

如果进程调用了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

Macro

Description

WIFEXITED(status)

True if status was returned for a child that terminated normally. In this case, we can execute

WEXITSTATUS (status)

to fetch the low-order 8 bits of the argument that the child passed to exit, _exit,or _Exit.

WIFSIGNALED (status)

True if status was returned for a child that terminated abnormally, by receipt of a signal that it didn’t catch. In this case, we can execute

WTERMSIG (status)

to fetch the signal number that caused the termination.

Additionally, some implementations (but not the Single UNIX Specification) define the macro

WCOREDUMP (status)

that returns true if a core file of the terminated process was generated.

WIFSTOPPED (status)

True if status was returned for a child that is currently stopped. In this case, we can execute

WSTOPSIG (status)

to fetch the signal number that caused the child to stop.

WIFCONTINUED (status)

True if status was returned for a child that has been continued after a job control stop (XSI extension to POSIX.1; waitpid only).

如果有很多的子进程,我们只想得到某个特定的子进程的终止状态,在一些版本的unix系统中的做法是,wait收到一个消息后判断它的PID是不是我们需要的,如果不是,再次运行wait(因为wait只要任何一个子进程结束,它就会返回)。从实用角度出发,POSIX.1定义了waitpid函数。

对于waitpidpid参数说明:

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运算,可以使用的常量如下:

Figure 8.7. The options constants for waitpid

Constant

Description

WCONTINUED

如果实现支持任务控制,任何由pid指定的子进程,它已经被停止,但仍然在运行,而且它的状态还没有被报告,那么返回它的状态。(XSI扩展到POSIX.1)(翻译的对么??)

WNOHANG

如果由pid指定的子进程当前不可用,waitpid函数将不阻塞。在本例中返回值为0。

WUNTRACED

如果实现支持任务控制,任何由pid指定的已经停止的子进程,由于它已经停止所没报告它的状态,那么返回它的状态。WIFSTOPPED宏判断返回值是否是相应的已经停止的子进程。

waitpid函数提供三种功能,但是并不提供给wait函数。

  1. waitpid函数让我们等待特定的进程,而wait函数返回任意已终止的子进程的状态。
  2. waitpid函数提供了一个非阻塞版本wait。当我们想得到子进程的状态,但是我们不想阻塞程序时。
  3. waitpid函数支持任务控制,可以使用WUNTRACEDWCONTINUED选项。

 

发表回复