Да, действительно, это правильный способ убедиться, что все ваши дети закончили, прежде чем вы продолжите:
pid_t pid;
...
while((pid = wait(NULL)) >= 0)
printf("child pid=%d ended.\n", pid); /* or whatever you want */
/* no more children active after this point, you don't need
* to check the value of errno, except if you allow this
* process to be interrupted by a signal. */
Это старое наследие процессов zomb ie (например, название для ходячие мертвецы mov ie): процесс zomb ie - это процесс, у которого есть exit(2)
ed и родительский элемент которого не имеет wait(2)
ed. У него освобождены все ресурсы, кроме записи в таблице процессов (в которой хранятся код выхода и учетные записи). Таким образом, когда родитель выполняет системный вызов wait(2)
, ядро может перемещаться по таблице своих дочерних процессов и проверять, должно ли оно вернуть ошибку (если список пуст), или есть какой-то дочерний элемент, который завершился и может вернуть свой код exit(2)
родителю. Вы можете правильно использовать wait(2)
(например, без ошибок), если вы ранее сделали fork(2)
, а wait(2)
сигнализирует об ошибке, если вы не создали дочерних процессов.
Чтобы получить время выполнения из детей вам нужно использовать один из альтернативных системных вызовов для wait(2)
(wait3(2)
или wait4(2)
, как указано в справочной странице FreeBSD, на linux есть аналогичные системные вызовы)
Попробуйте это просто пример:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define N 7
#define PARENT_SLEEP 30
#define CHILD_MAXSLEEP 60
int main()
{
int i;
pid_t mypid = getpid();
for(i = 0; i < N; i++) {
pid_t chpid = fork();
switch (chpid) {
case -1: /* error */
fprintf(stderr,
"Parent [pid=%d]: fork: %s\n",
mypid,
strerror(errno));
goto out; /* we want to break the loop */
case 0: /* child */
/* reinit mypid to reflect proper value */
mypid = getpid();
printf("Child [pid=%d]: start\n", mypid);
/* we initialize random module after fork, so
* all children don't get the same random
* sequence. Probably all of them will take
* the same value for the time, so we use also
* the pid for the seed to be different for
* each child. */
srandom( mypid ^ time(NULL) );
/* a random time between 1 and CHILD_MAXSLEEP */
int myrandom = random() % CHILD_MAXSLEEP + 1;
printf("Child [pid=%d]: wait for %d secs.\n",
mypid, myrandom);
sleep( myrandom );
printf("Child [pid=%d]: exiting with code=%d\n",
mypid, myrandom);
exit( myrandom );
default: /* parent */
printf("Parent[pid=%d]: I have started"
" child (pid = %d)\n", mypid, chpid);
break;
} /* switch */
} /* for */
out:
/* if you put a delay here, before doing wait()s,
* and you execute a ps(1) command before the parent
* begins to make waits, and some of the children have
* already died, you'll see the zombie processes
* (they are marked with a Z in status) */
printf("Parent [pid=%d]: sleeping for %ds.\n",
mypid, PARENT_SLEEP);
sleep(PARENT_SLEEP);
printf("Parent [pid=%d]: beginning to wait.\n",
mypid);
int status;
pid_t child;
while ((child = wait(&status)) >= 0) {
printf("Parent[pid=%d]: "
"detected exit(%d) from "
"child(pid=%d)\n",
mypid,
WEXITSTATUS(status),
child);
}
printf("Parent[pid=%d]: exiting\n", mypid);
exit(0);
} /* main */
и один пример одного исполнения:
$ a.out
Parent[pid=81452]: I have started child (pid = 81453)
Parent[pid=81452]: I have started child (pid = 81454)
Parent[pid=81452]: I have started child (pid = 81455)
Parent[pid=81452]: I have started child (pid = 81456)
Child [pid=81453]: start
Child [pid=81453]: wait for 34 secs.
Child [pid=81455]: start
Child [pid=81455]: wait for 56 secs.
Child [pid=81456]: start
Child [pid=81456]: wait for 42 secs.
Parent[pid=81452]: I have started child (pid = 81457)
Parent[pid=81452]: I have started child (pid = 81458)
Parent[pid=81452]: I have started child (pid = 81459)
Parent [pid=81452]: sleeping for 30s.
Child [pid=81454]: start
Child [pid=81454]: wait for 9 secs.
Child [pid=81457]: start
Child [pid=81457]: wait for 58 secs.
Child [pid=81458]: start
Child [pid=81458]: wait for 30 secs.
Child [pid=81459]: start
Child [pid=81459]: wait for 14 secs.
Child [pid=81454]: exiting with code=9
Child [pid=81459]: exiting with code=14
Child [pid=81458]: exiting with code=30
Parent [pid=81452]: beginning to wait. <<<<< before this message, you can see Zombie processes.
Parent[pid=81452]: detected exit(14) from child(pid=81459)
Parent[pid=81452]: detected exit(30) from child(pid=81458)
Parent[pid=81452]: detected exit(9) from child(pid=81454)
Child [pid=81453]: exiting with code=34
Parent[pid=81452]: detected exit(34) from child(pid=81453)
Child [pid=81456]: exiting with code=42
Parent[pid=81452]: detected exit(42) from child(pid=81456)
Child [pid=81455]: exiting with code=56
Parent[pid=81452]: detected exit(56) from child(pid=81455)
Child [pid=81457]: exiting with code=58
Parent[pid=81452]: detected exit(58) from child(pid=81457)
Parent[pid=81452]: exiting
$ _