Основы программирования в Linux
<b>#include <sys/types.h></b><b>#include <sys/wait.h></b><b>pid_t wait(int *stat_loc);</b>Системный вызов
заставляет родительский процесс сделать паузу до тех пор, пока один из его дочерних процессов не остановится. Вызов возвращает PID дочернего процесса. Обычно это дочерний процесс, который завершился. Сведения о состоянии позволяют родительскому процессу определить статус завершения дочернего процесса, т.е. значение, возвращенное из функцииwaitили переданное функцииmain. Еслиexitне равен пустому указателю, информация о состоянии будет записана в то место, на которое указывает этот параметр.stat_locИнтерпретировать информацию о состоянии процесса можно с помощью макросов, описанных в файле sys/wait.h и приведенных в табл. 11.2.
Таблица 11.2
Макрос Описание WIFEXITED(stat_val)Ненулевой, если дочерний процесс завершен нормально WEXITSTATUS(stat_val)Если ненулевой, возвращает код завершения дочернего процессаWIFEXITEDWIFSIGNALED(stat_val)Ненулевой, если дочерний процесс завершается неперехватываемым сигналом WTERMSIG(stat_val)Если ненулевой, возвращает номер сигналаWIFSIGNALEDWIFSTOPPED(stat_val)Ненулевой, если дочерний процесс остановился WSTOPSIG(stat_val)Если ненулевой, возвращает номер сигналаWIFSTOPPEDВыполните упражнение 11.4.
Упражнение 11.4. Системный вызовwaitВ этом упражнении вы слегка измените программу, чтобы можно было подождать и проверить код состояния дочернего процесса. Назовите новую программу wait.c.
#include <sys/types.h><i>#include <sys/wait.h></i>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main() {pid_t pid;char* message;int n;<i> int exit_code;</i>printf("fork program starting\n");pid = fork();switch(pid) {case -1:perror("fork failed");exit(1);case 0:message = "This is the child";n = 5;<i> exit_code = 37;</i>break;default:message = "This is the parent";n = 3;<i> exit_code = 0;</i>break;}for (; n > 0; n--) {puts(message);sleep(1);}Следующий фрагмент программы ждет окончания дочернего процесса:
if (pid != 0) {int stat_val;pid_t child_pid;child_pid = wait(&stat_val);printf("Child has finished: PID = %d\n", child_pid);if (WIFEXITED(stat_val))printf("Child exited with code %d\n", WEXITSTATUS(stat_val));else printf("Child terminated abnormally\n");}exit(exit_code);}Когда вы выполните эту программу, то увидите, что родительский процесс ждет дочерний:
$ <b>./wait</b>fork program startingThis is the childThis is the parentThis is the parentThis is the childThis is the parentThis is the childThis is the childThis is the childChild has finished: PID = 1582Child exited with code 37$Как это работает
Родительский процесс, получивший ненулевое значение, возвращенное из вызова
, применяет системный вызовforkдля приостановки своего выполнения до тех пор, пока информация о состоянии дочернего процесса не станет доступной. Это произойдет, когда дочерний процесс вызовет функциюwait; мы присвоили ему код завершения 37. Далее родительский процесс продолжается, определяет, протестировав значение, возвращенное вызовомexit, что дочерний процесс завершился нормально, и извлекает код завершения из информации о состоянии процесса.waitПроцессы-зомби
Применение вызова
для создания процессов может оказаться очень полезным, но вы должны отслеживать дочерние процессы. Когда дочерний процесс завершается, связь его с родителем сохраняется до тех пор, пока родительский процесс в свою очередь не завершится нормально, или не вызоветfork. Следовательно, запись о дочернем процессе не исчезает из таблицы процессов немедленно. Становясь неактивным, дочерний процесс все еще остается в системе, поскольку его код завершения должен быть сохранен, на случай если родительский процесс в дальнейшем вызоветwait. Он становится умершим или процессом-зомби.wait