有时候我们希望子进程继续执行,而父进程阻塞直到子进程完成任务。这个时候我们可以调用wait或者waitpid系统调用.
当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。父进程可以忽略该信号,或调用信号处理函数。调用wait或waitpid的进程,会发生以下情况:
1). 如果其所有子进程都在运行,则该进程阻塞
2). 如果一个子进程已经终止,正等待父进程获取其终止状态,则取得该进程的终止状态立即返回
3). 如果它没有任何子进程,则立即出错返回。
#include <sys/wait.h>
#pid_t wait (int * statloc);
#pid_t waitpid (pid_t pid, int * statloc, int optins);
参数
参数statloc用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL
如果参数status的值不是NULL,wait就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程是正常退出还是被非正常结束的(一个进程也可以被其他进程用信号结束,我们将在以后的文章中介绍),以及正常结束时的返回值,或被哪一个信号结束的等信息。由于这些信息被存放在一个整数的不同二进制位中,所以用常规的方法读取会非常麻烦,人们就设计了一套专门的宏(macro)来完成这项工作,
WIFEXITED(status)
若为正常终止子进程返回的状态,则为真。对于这种情况可以执行WEXITSTATUS(status),取子进程传送给exit、_exit或_Exit参数的低8位。
WIFSIGNALED(status)
若为异常终止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况可以执行WTERMSIG(status),取得子进程终止的信号编号。
WIFSTOPPED(status)
若为当前暂停子进程返回的状态,则为真。对于这种情况可以执行WSTOPSIG(status),取得子进程暂停的信号编号。
WIFCONTINUED(status)
若在作业控制暂停后已经继续的子进程返回的状态,则为真。仅用于waitpid。
WIFSTOPPEN 子进程处于暂停执行状态,则返回非0值
WSTOPSIG 若子进程处于暂停状态,则它取得引发子进程暂停的信号代码
返回值
如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。
wait和waitpid函数区别
1). 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。
2). waitpid并不等待在其调用之后的第一个终止子进程,它有若干个选项,可以控制它所等到的进程。
3). 对于wait,其唯一的出错是调用进程没有子进程;对于waitpid,假如指定的进程或进程组不存在,或者参数pid指定的进程不是调用进程的子进程都可能出错。
4). Waitpid提供了wait没有的三个功能:一是waitpid可等待一个特定的进程;二是waitpid提供了一个waitpid的非阻塞版本;三是waitpid支持作业控制。
对于waitpid函数中的pid参数的作用见下表:
pid == -1 等待任一子进程。
pid > 0 等待其进程ID与pid相等的子进程
pid == 0 等待其组ID等于调用进程组ID的任一的子进程
pid < -1 等待其组ID等于pid绝对值的任一的子进程
对于waitpid函数中的options参数的作用见下表:
WCONTINUED
若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但是状态没报告,则返回其状态
WNOHANG
若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时返回值为0
WUNTRACED
若实现支持作业控制,那么由pid指定的任一子进程已经处于暂停状态并没报告过,则返回其状态
0
同wait