waitpid() - Unix,Linux 系统调用
Tutorials Point


  Unix 初学者指南
  Unix Shell 编程
  高级 Unix
  Unix 有用参考
  Unix 有用资源
  精选阅读

版权所有 © 2014 tutorialspoint



  首页     参考     讨论论坛     关于 TP  

waitpid() - Unix,Linux 系统调用


previous next AddThis Social Bookmark Button

广告

名称

wait, waitpid - 等待进程状态改变

语法

#include <sys/types.h> 
#include <sys/wait.h> 

pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); int waitid(idtype_t idtype, id_t id, siginfo_t * infop , int options );

描述

所有这些系统调用都用于等待调用进程子进程的状态变化,并获取有关状态已更改的子进程的信息。状态更改被认为是:子进程终止;子进程被信号停止;或子进程被信号恢复。对于终止的子进程,执行 wait 允许系统释放与子进程关联的资源;如果没有执行 wait,则终止的子进程将保持“僵尸”状态(请参见下面的注释)。

如果子进程已经更改状态,则这些调用立即返回。否则,它们将阻塞,直到子进程更改状态或信号处理程序中断调用(假设系统调用不会使用 **sigaction**(2) 的 **SA_RESTART** 标志自动重新启动)。在本页的其余部分,状态已更改且尚未由这些系统调用之一等待的子进程称为 *可等待的*。

wait() 和 waitpid()

**wait**() 系统调用挂起当前进程的执行,直到其一个子进程终止。调用 *wait(&status)* 等效于

    waitpid(-1, &status, 0);

**waitpid**() 系统调用挂起当前进程的执行,直到由 *pid* 参数指定的子进程更改状态。默认情况下,**waitpid**() 仅等待终止的子进程,但此行为可以通过 *options* 参数进行修改,如下所述。

*pid* 的值可以是

标签描述
< -1 表示等待任何进程组 ID 等于 *pid* 的绝对值的子进程。
-1 表示等待任何子进程。
0 表示等待任何进程组 ID 等于调用进程的进程组 ID 的子进程。
> 0 表示等待进程 ID 等于 *pid* 值的子进程。

*options* 的值是以下常量之一或多个的 OR

标签描述
WNOHANG如果没有任何子进程退出,则立即返回。
WUNTRACED 如果子进程已停止(但未通过 **ptrace**(2) 跟踪),则也返回。即使未指定此选项,也会提供已停止的 *跟踪* 子进程的状态。
WCONTINUED (自 Linux 2.6.10 起)如果已停止的子进程已通过传递 **SIGCONT** 恢复,则也返回。

(对于仅限 Linux 的选项,请参见下文。)仅当 **SIGCHLD** 信号未设置 **SA_NOCLDSTOP** 标志时,**WUNTRACED** 和 **WCONTINUED** 选项才有效(请参见 **sigaction**(2))。

如果 *status* 不为 NULL,**wait**() 和 **waitpid**() 会将状态信息存储到它指向的 *int* 中。可以使用以下宏检查此整数(这些宏将整数本身作为参数,而不是指向它的指针,就像在 **wait**() 和 **waitpid**() 中一样!)

标签描述
**WIFEXITED(**status**)如果子进程正常终止,则返回 true,即通过调用 **exit**(3) 或 **_exit**(2),或从 main() 返回。
**WEXITSTATUS(**status**)返回子进程的退出状态。它由子进程在调用 **exit**() 或 **_exit**() 或作为 main() 中 return 语句的参数时指定的 *status* 参数的最低有效 16-8 位组成。只有当 **WIFEXITED** 返回 true 时,才应使用此宏。
**WIFSIGNALED(**status**)如果子进程被信号终止,则返回 true。
**WTERMSIG(**status**)返回导致子进程终止的信号编号。只有当 **WIFSIGNALED** 返回 true 时,才应使用此宏。
**WCOREDUMP(**status**)如果子进程生成了核心转储,则返回 true。只有当 **WIFSIGNALED** 返回 true 时,才应使用此宏。此宏未在 POSIX.1-2001 中指定,并且在某些 Unix 实现(例如 AIX、SunOS)上不可用。仅在 #ifdef WCOREDUMP ... #endif 中使用它。
**WIFSTOPPED(**status**)如果子进程因信号传递而停止,则返回 true;这只有在使用 **WUNTRACED** 或子进程正在被跟踪(请参见 **ptrace**(2))时才有可能。
**WSTOPSIG(**status**)返回导致子进程停止的信号编号。只有当 **WIFSTOPPED** 返回 true 时,才应使用此宏。
**WIFCONTINUED(**status**)(自 Linux 2.6.10 起)如果子进程已通过传递 **SIGCONT** 恢复,则返回 true。

waitid()

**waitid**() 系统调用(自 Linux 2.6.9 起可用)提供了对要等待哪些子进程状态更改的更精确的控制。

*idtype* 和 *id* 参数选择要等待的子进程,如下所示

标签描述
*idtype* == **P_PID**等待进程 ID 与 *id* 匹配的子进程。
*idtype* == **P_PGID**等待任何进程组 ID 与 *id* 匹配的子进程。
*idtype* == **P_ALL**等待任何子进程;*id* 被忽略。
要等待的子进程状态更改通过在 *options* 中对以下标志之一或多个进行 OR 来指定
WEXITED 等待已终止的子进程。
WSTOPPED 等待因信号传递而停止的子进程。
WCONTINUED 等待(先前已停止的)已通过传递 **SIGCONT** 恢复的子进程。
以下标志还可以与 *options* 进行 OR 运算
WNOHANG 与 **waitpid**() 相同。
WNOWAIT 使子进程保持可等待状态;以后的 wait 调用可用于再次检索子进程状态信息。
成功返回后,**waitid**() 将填充 *infop* 指向的 **siginfo_t** 结构的以下字段
si_pid 子进程的进程 ID。
si_uid 子进程的真实用户 ID。(此字段在大多数其他实现中未设置。)
si_signo 始终设置为 **SIGCHLD**。
si_status 子进程的退出状态,如传递给 **_exit**(2)(或 **exit**(3)),或导致子进程终止、停止或继续的信号。 *si_code* 字段可用于确定如何解释此字段。
si_code 设置为以下之一:**CLD_EXITED**(子进程调用 **_exit**(2));**CLD_KILLED**(子进程被信号杀死);**CLD_STOPPED**(子进程被信号停止);或 **CLD_CONTINUED**(子进程被 **SIGCONT** 继续)。

如果在 *options* 中指定了 **WNOHANG** 并且没有任何子进程处于可等待状态,则 **waitid**() 将立即返回 0,并且 *infop* 指向的 **siginfo_t** 结构的状态未定义。为了区分这种情况与子进程处于可等待状态的情况,在调用之前将 *si_pid* 字段清零,并在调用返回后检查此字段中的非零值。

返回值

**wait**():成功时,返回终止的子进程的进程 ID;错误时,返回 -1。

**waitpid**():成功时,返回状态已更改的子进程的进程 ID;错误时,返回 -1;如果指定了 **WNOHANG** 并且 *pid* 指定的子进程尚未更改状态,则返回 0。

**waitid**():成功时或如果指定了 **WNOHANG** 并且 *id* 指定的子进程尚未更改状态时返回 0;错误时返回 -1。

在发生错误的情况下,这些调用中的每一个都会将 *errno* 设置为适当的值。

错误

标签描述
ECHILD (对于 **wait**())调用进程没有任何未等待的子进程。
ECHILD (对于 **waitpid**() 或 **waitid**())由 *pid*(**waitpid**())或 *idtype* 和 *id*(**waitid**())指定的进程不存在或不是调用进程的子进程。(如果 SIGCHLD 的操作设置为 SIG_IGN,则对于自己的子进程也可能发生这种情况。另请参见关于线程的 LINUX 注释部分。)
EINTR 未设置 **WNOHANG**,并且捕获了未阻塞的信号或 **SIGCHLD**。
EINVAL *options* 参数无效。

注释

如果一个子进程终止,但父进程尚未对其执行等待操作,则该子进程将成为一个“僵尸”进程。内核会维护关于僵尸进程的一组最小信息(PID、终止状态、资源使用信息),以便父进程稍后执行等待操作以获取有关子进程的信息。

只要僵尸进程没有通过等待操作从系统中移除,它就会占用内核进程表中的一个槽位,如果该表填满,则将无法创建更多进程。如果父进程终止,则其“僵尸”子进程(如果有)将由**init**(8) 采用,**init**(8) 会自动执行等待操作以移除僵尸进程。

POSIX.1-2001 规定,如果**SIGCHLD** 的处理方式设置为**SIG_IGN** 或为**SIGCHLD** 设置了**SA_NOCLDWAIT** 标志(参见**sigaction**(2)),则终止的子进程不会变成僵尸进程,并且对**wait**() 或**waitpid**() 的调用将阻塞,直到所有子进程都终止,然后以**ECHILD** 设置的*errno* 失败。(原始 POSIX 标准未指定将**SIGCHLD** 设置为**SIG_IGN** 的行为。)Linux 2.6 符合此规范。但是,Linux 2.4(及更早版本)不符合:如果在忽略**SIGCHLD** 时进行**wait**() 或**waitpid**() 调用,则该调用的行为就像没有忽略**SIGCHLD** 一样,也就是说,该调用会阻塞,直到下一个子进程终止,然后返回该子进程的进程 ID 和状态。

LINUX 注释

在 Linux 内核中,内核调度线程与进程不是一个独立的构造。相反,线程只是一个使用 Linux 独有的**clone**(2) 系统调用创建的进程;其他例程(例如可移植的**pthread_create**(3) 调用)使用**clone**(2) 实现。

在 Linux 2.4 之前,线程只是进程的一种特殊情况,因此一个线程不能等待另一个线程的子进程,即使后者属于同一个线程组。但是,POSIX 规定了这样的功能,并且从 Linux 2.4 开始,线程可以并且默认情况下会等待同一线程组中其他线程的子进程。

以下 Linux 特定的*选项*用于使用**clone**(2) 创建的子进程;它们不能与**waitid**() 一起使用。

标签描述
__WCLONE 仅等待“clone”子进程。如果省略,则仅等待“非 clone”子进程。(“clone”子进程是在终止时不会向其父进程传递任何信号或除**SIGCHLD** 之外的信号的子进程。)如果也指定了**__WALL**,则忽略此选项。
__WALL (自 Linux 2.4 起)等待所有子进程,无论类型(“clone”或“非 clone”)。
__WNOTHREAD (自 Linux 2.4 起)不等待同一线程组中其他线程的子进程。这是 Linux 2.4 之前的默认设置。

示例

以下程序演示了**fork**(2) 和**waitpid**(2) 的用法。该程序创建一个子进程。如果未向程序提供命令行参数,则子进程使用**pause**(2) 挂起其执行,以允许用户向子进程发送信号。否则,如果提供命令行参数,则子进程立即退出,使用命令行上提供的整数作为退出状态。父进程执行一个循环,使用**waitpid**(2) 监视子进程,并使用上面描述的 W*() 宏分析等待状态值。

以下 shell 会话演示了程序的用法。

$ ./a.out & Child PID is 32360 [1] 32359 $ kill -STOP 32360 stopped by signal 19 $ kill -CONT 32360 continued $ kill -TERM 32360 killed by signal 15 [1]+ Done ./a.out $

#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); } }

符合标准

SVr4、4.3BSD、POSIX.1-2001。

参见



previous next Printer Friendly

广告


  

广告



广告