/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2017. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 26-1 */
#include <sys/wait.h>
#include <time.h>
#include "curr_time.h" /* Declaration of currTime() */
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
int numDead; /* Number of children so far waited for */
pid_t childPid; /* PID of waited for child */
int j;
if (argc < 2 || strcmp(argv[1], "--help") == 0)
usageErr("%s sleep-time...\n", argv[0]);
setbuf(stdout, NULL); /* Disable buffering of stdout */
for (j = 1; j < argc; j++) { /* Create one child for each argument */
switch (fork()) {
case -1:
errExit("fork");
case 0: /* Child sleeps for a while then exits */
printf("[%s] child %d started with PID %ld, sleeping %s "
"seconds\n", currTime("%T"), j, (long) getpid(),
argv[j]);
sleep(getInt(argv[j], GN_NONNEG, "sleep-time"));
_exit(EXIT_SUCCESS);
default: /* Parent just continues around loop */
break;
}
}
numDead = 0;
for (;;) { /* Parent waits for each child to exit */
childPid = wait(NULL);
if (childPid == -1) {
if (errno == ECHILD) {
printf("No more children - bye!\n");
exit(EXIT_SUCCESS);
} else { /* Some other (unexpected) error */
errExit("wait");
}
}
numDead++;
printf("[%s] wait() returned child PID %ld (numDead=%d)\n",
currTime("%T"), (long) childPid, numDead);
}
}
执行结果
root@ubuntu:~/tlpi-book/procexec# ./multi_wait 1 2 3 4 5
[15:14:31] child 1 started with PID 28487, sleeping 1 seconds
[15:14:31] child 2 started with PID 28488, sleeping 2 seconds
[15:14:31] child 3 started with PID 28489, sleeping 3 seconds
[15:14:31] child 4 started with PID 28490, sleeping 4 seconds
[15:14:31] child 5 started with PID 28491, sleeping 5 seconds
[15:14:32] wait() returned child PID 28487 (numDead=1)
[15:14:33] wait() returned child PID 28488 (numDead=2)
[15:14:34] wait() returned child PID 28489 (numDead=3)
[15:14:35] wait() returned child PID 28490 (numDead=4)
[15:14:36] wait() returned child PID 28491 (numDead=5)
No more children - bye!
该程序创建多个子进程,每个子进程对应于一个(整型)命令行参数。每个子进程休眠若干秒后退出,休眠时间分别由相应各命令行参数指定,在创建所有子进程之后,父进程循环调用wait()来监控这些子进程的终止。而直到wait()返回-1时才会退出循环。当调用进程并无之前未被等待的子进程,此时会将errno置为ECHILD。
系统调用waitpid()
系统调用waitpid()存在诸多限制,而设计waitpid()则意在突破这些限制。
如果父进程创建了多个子进程,使用wait()将无法等待某个特定子进程的完成,只能按顺序等待下一个子进程的终止。
如果没有子进程退出,wait()总是保持阻塞。有时会希望之星非阻塞的等待:是否有子进程退出,立判可知。
使用wait()只能发现那些已终止的子进程。对于子进程因某个信号(SIGSTOP SIGTTIN)而停止,或是已停止子进程收到SIGCONT信号后恢复之星的情况就无能为力了。
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2017. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 or (at your option) *
* any later version. This program is distributed without any warranty. *
* See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 26-2 */
#define _GNU_SOURCE /* Get strsignal() declaration from <string.h> */
#include <string.h>
#include <sys/wait.h>
#include "print_wait_status.h" /* Declaration of printWaitStatus() */
#include "tlpi_hdr.h"
/* NOTE: The following function employs printf(), which is not
async-signal-safe (see Section 21.1.2). As such, this function is
also not async-signal-safe (i.e., beware of calling it from a
SIGCHLD handler). */
void /* Examine a wait() status using the W* macros */
printWaitStatus(const char *msg, int status)
{
if (msg != NULL)
printf("%s", msg);
if (WIFEXITED(status)) {
printf("child exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("child killed by signal %d (%s)",
WTERMSIG(status), strsignal(WTERMSIG(status)));
#ifdef WCOREDUMP /* Not in SUSv3, may be absent on some systems */
if (WCOREDUMP(status))
printf(" (core dumped)");
#endif
printf("\n");
} else if (WIFSTOPPED(status)) {
printf("child stopped by signal %d (%s)\n",
WSTOPSIG(status), strsignal(WSTOPSIG(status)));
#ifdef WIFCONTINUED /* SUSv3 has this, but older Linux versions and
some other UNIX implementations don't */
} else if (WIFCONTINUED(status)) {
printf("child continued\n");
#endif
} else { /* Should never happen */
printf("what happened to this child? (status=%x)\n",
(unsigned int) status);
}
}
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2017. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 26-3 */
#include <sys/wait.h>
#include "print_wait_status.h" /* Declares printWaitStatus() */
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
int status;
pid_t childPid;
if (argc > 1 && strcmp(argv[1], "--help") == 0)
usageErr("%s [exit-status]\n", argv[0]);
switch (fork()) {
case -1: errExit("fork");
case 0: /* Child: either exits immediately with given
status or loops waiting for signals */
printf("Child started with PID = %ld\n", (long) getpid());
if (argc > 1) /* Status supplied on command line? */
exit(getInt(argv[1], 0, "exit-status"));
else /* Otherwise, wait for signals */
for (;;)
pause();
exit(EXIT_FAILURE); /* Not reached, but good practice */
default: /* Parent: repeatedly wait on child until it
either exits or is terminated by a signal */
for (;;) {
childPid = waitpid(-1, &status, WUNTRACED
#ifdef WCONTINUED /* Not present on older versions of Linux */
| WCONTINUED
#endif
);
if (childPid == -1)
errExit("waitpid");
/* Print status in hex, and as separate decimal bytes */
printf("waitpid() returned: PID=%ld; status=0x%04x (%d,%d)\n",
(long) childPid,
(unsigned int) status, status >> 8, status & 0xff);
printWaitStatus(NULL, status);
if (WIFEXITED(status) || WIFSIGNALED(status))
exit(EXIT_SUCCESS);
}
}
}
执行过程: