Книга: Основы программирования в Linux

Дублирование образа процесса

Дублирование образа процесса

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

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

#include <sys/types.h>
#include <unistd.h>
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 <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
 pid_t pid;
 char* message;
 int n;
 printf("fork program startingn");
 pid = fork();
 switch(pid) {
 case -1:
  perror("fork failed");
  exit(1);
 case 0:
  message = "This is the child";
  n = 5;
  break;
 default:
  message = "This is the parent";
  n = 3;
  break;
 }
 for (; n > 0; n--) {
  puts(message);
  sleep(1);
 }
 exit(0);
}

Эта программа выполняет два процесса. Дочерний процесс создается и выводит пять раз сообщение. Исходный процесс (родитель) выводит сообщение только три раза. Родительский процесс завершается до того, как дочерний процесс выведет все свои сообщения, поэтому в вывод попадает очередное приглашение командной оболочки.

$ ./fork1
fork program starting
This is the child
This is the parent
This is the parent
This is the child
This is the parent
This is the child
$ This is the child
This is the child

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

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

Оглавление книги


Генерация: 1.137. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз