printf("Done.\n");

 exit(0);

}

Когда вы выполните эту программу, рехес.с, то получите обычный вывод команды ps, но без сообщения Done. Кроме того, обратите внимание на то, что в выводе нет процесса с именем рехес:

$ ./рехес

Running ps with execlp

 PID TTY   STAT TIME COMMAND

1    ?     S    0:03 init [5]

...

1262 pts/1 Ss   0:00 /bin/bash

1273 pts/2 S    0:00 su -

1274 pts/2 S+   0:00 -bash

1463 pts/1 SN   0:00 oclock

1465 pts/1 S    0:01 emacs Makefile

1514 pts/1 R+   0:00 ps ax

Как это работает

Программа выводит первое сообщение и затем вызывает функцию execlp, которая ищет каталоги, заданные в переменной окружения PATH для обнаружения программы ps. Далее она выполняет команду вместо программы рехес, запустив ее так, как будто вы ввели команду командной оболочки

$ ps ax

Когда ps завершается, вы получаете новую строку приглашения командной оболочки. Возврата в программу рехес не происходит, поэтому второе сообщение не выводится. PID нового процесса тот же, что и у исходного, то же самое можно сказать о PID родительского процесса и значении nice. В сущности, происходит следующее: выполняющаяся программа запустила на выполнение новый код и новый исполняемый файл, заданный в вызове функции exec.

Существует ограничение для общего размера списка аргументов и окружения процесса, запускаемого функциями exec. Оно задается в переменной ARG_MAX и в системах Linux равно 128 Кбайт. В других системах может задаваться меньший предельный размер, что способно порождать проблемы. Стандарт POSIX гласит, что ARG_MAX должна быть не менее 4096 байтов.

Функции exec, как правило, не возвращаются в программу до тех пор, пока не возникла ошибка, в этом случае задается переменная errno и функция exec возвращает -1.

Новые процессы, запущенные exec, наследуют многие свойства исходного процесса. В частности, открытые файловые дескрипторы остаются открытыми в новом процессе, пока не установлен их флаг FD_CLOEXEC (close on exec) (подробную информацию см. в описании системного вызова fcntl в главе 3). Любые открытые в исходном процессе потоки каталогов закрываются.

<p>Дублирование образа процесса</p>

Для применения процессов, выполняющих несколько функций одновременно, можно либо использовать потоки, обсуждаемые в главе 12, либо создавать в программе полностью отдельный процесс, как делает init, вместо замещения текущего потока исполнения, как в случае применения функции exec.

Создать новый процесс можно с помощью вызова fork. Системный вызов дублирует текущий процесс, создавая новый элемент в таблице процессов с множеством атрибутов, таких же как у текущего процесса. Новый процесс почти идентичен исходному, выполняет тот же программный код, но в своем пространстве данных, окружении и со своими файловыми дескрипторами. В комбинации с функциями exec вызов fork — все, что вам нужно для создания новых процессов.

#include

#include

pid_t fork(void);

Как видно из рис. 11.2, вызов fork возвращает в родительский процесс PID нового дочернего процесса. Новый процесс продолжает выполнение так же, как и исходный, за исключением того, что в дочерний процесс вызов fork возвращает 0. Это позволяет родительскому и дочернему процессам определить, "кто есть кто".

Рис. 11.2 

Если вызов fork завершается аварийно, он возвращает -1. Обычно это происходит из-за ограничения числа дочерних процессов, которые может иметь родительский процесс (CHILD_MAX), в этом случае переменной errno будет присвоено значение EAGAIN. Если для элемента таблицы процессов недостаточно места или не хватает виртуальной памяти, переменная errno получит значение ENOMEM.

Далее приведен фрагмент типичного программного кода, использующего вызов fork:

pid_t new_pid;

new_pid = fork();

switch(new_pid) {

case -1:

 /* Ошибка */

 break;

case 0:

 /* Мы — дочерний процесс */

 break;

default:

 /* Мы — родительский процесс */

 break;

}

Выполните упражнение 11.3.

Упражнение 11.3. Системный вызов fork

Давайте рассмотрим простой пример fork1.с:

#include

#include

#include

#include

int main() {

 pid_t pid;

 char* message;

 int n;

 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;

  break;

 default:

Перейти на страницу:

Похожие книги