Литмир - Электронная Библиотека
A
A

Обратите внимание, что этот макрос не стандартный. Системы GNU/Linux, Solaris и BSD его поддерживают, однако некоторые другие системы Unix нет. Поэтому и здесь, если нужно его использовать, заключите код внутрь '

#ifdef WCOREDUMP ... #endif
'.

Большинство программ не интересуются, почему завершился порожденный процесс; им просто нужно, что он завершился, возможно, отметив, было завершение успешным или нет. Программа GNU Coreutils

install
демонстрирует такое простое использование
fork()
,
execlp()
и
wait()
. Опция
-s
заставляет
install
запустить для устанавливаемого двоичного исполняемого файла программу
strip
.
(strip
удаляет из исполняемого файла отладочную и прочую информацию. Это может сохранить значительное пространство. На современных системах с многогигабайтными жесткими дисками при установке редко бывает необходимо использовать
strip
для исполняемых файлов.) Вот функция
strip()
из
install.с
:

513 /* Вырезать таблицу имен из файла PATH.

514    Мы могли бы сначала вытащить из файла магическое число

515    для определения, нужно ли вырезать, но заголовочные файлы и

516    магические числа варьируют от системы к системе так сильно, что

517    сделать его переносимым было бы очень трудно. Не стоит усилий. */

518

519 static void

520 strip (const char *path)

521 {

522  int status;

523  pid_t pid = fork();

524

525  switch (pid)

526  {

527  case -1:

528   error(EXIT_FAILURE, errno, _("fork system call failed"));

529   break;

530  case 0: /* Порожденный. */

531   execlp("strip", "strip", path, NULL);

532   error(EXIT_FAILURE, errno, _("cannot run strip"));

533   break;

534  default: /* Родитель. */

535   /* Родительский процесс. */

536   while (pid != wait(&status)) /* Ждать завершения потомка. */

537    /* Ничего не делать. */ ;

538   if (status)

539    error(EXIT_FAILURE, 0, _("strip failed"));

540   break;

541  }

542 }

Строка 523 вызывает

fork()
. Затем оператор
switch
предпринимает нужное действие для возвращения ошибки (строки 527–529), порожденного процесса (строки 530–533) и родительского процесса (строки 534–539).

Стиль строк 536–537 типичен; они ожидают завершения нужного порожденного процесса. Возвращаемое значение wa

it()
является PID этого потомка. Оно сравнивается с PID порожденного процесса,
status
проверяется лишь на предмет равенства нулю (строка 538), в случае ненулевого результата потомок завершился неудачно. (Тест, хотя и правильный, грубый, но простой. Более правильным был бы тест наподобие '
if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
'.)

Из описаний и кода, представленных до сих пор, может показаться, что родительские программы должны выбрать определенный момент, чтобы ожидать завершения любого порожденного процесса, возможно, с опросом в цикле (как делает

install.c
), ожидая всех потомков. В разделе 10.8.3 «Родительский надзор: три различные стратегии» мы увидим, что это необязательно. Скорее, сигналы предоставляют ряд механизмов для использования уведомлениями родителей о завершении порожденных процессов.

9.1.6.2. Использование функций BSD:

wait3()
и
wait4()

Системные вызовы BSD

wait3()
и
wait4()
полезны, если вы интересуетесь ресурсами, использованными порожденным процессом. Функции нестандартны (что означает, что они не являются частью POSIX), но широко доступны, в том числе на GNU/Linux. Объявления следующие:

#include <sys/types.h> /* Обычный */

#include <sys/time.h>

 /* Под GNU/Linux не нужно, но улучшает переносимость */

#include <sys/resource.h>

#include <sys/wait.h>

pid_t wait3(int *status, int options, struct rusage *rusage);

pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);

Переменная

status
та же, что и для
wait()
и
waitpid()
. Все описанные ранее макросы (
WIFEXITED()
и т.д.) могут использоваться и с ними.

Значение

options
также то же самое, что и для
waitpid()
: либо 0, либо побитовое ИЛИ с одним или обоими флагами
WNOHANG
и
WUNTRACED
.

wait3()
ведет себя подобно
wait()
, получая сведения о первом доступном порожденном зомби, a
wait4()
подобна
waitpid()
, получая сведения об определенном процессе. Обе функции возвращают PID потомка, -1 при ошибке или 0, если нет доступных процессов и был использован флаг
WNOHANG
. Аргумент
pid
может принимать те же значения, что и аргумент
pid
для
waitpid()
.

Ключевым отличием является указатель

struct rusage
. Если он не равен
NULL
, система заполняет ее сведениями о процессе. Эта структура описана в POSIX и в справочной странице getrusage(2):

120
{"b":"576259","o":1}