Форк системного вызова Linux

Системный вызов fork используется для создания новых процессов. Вновь созданный процесс является дочерним процессом. Процесс, который вызывает fork и создает новый процесс, является родительским процессом. Дочерний и родительский процессы выполняются одновременно.

Но дочерний и родительский процессы находятся в разных областях памяти. Эти пространства памяти имеют одинаковое содержимое, и любая операция, выполняемая одним процессом, не повлияет на другой процесс.

Когда дочерние процессы созданы; теперь оба процесса будут иметь один и тот же программный счетчик (ПК), поэтому оба этих процесса будут указывать на одну и ту же следующую инструкцию. Файлы, открытые родительским процессом, будут такими же для дочернего процесса.

Дочерний процесс точно такой же, как и его родительский процесс, но есть различия в идентификаторах процессов:

  1. Идентификатор дочернего процесса — это уникальный идентификатор процесса, который отличается от идентификаторов всех других существующих процессов.
  2. Идентификатор родительского процесса будет таким же, как и этот идентификатора процесса родительского дочернего процесса.

Свойства дочернего процесса

Ниже приведены некоторые из свойств, которые имеет дочерний процесс:

  1. Счетчики ЦП и использование ресурсов инициализируются для сброса до нуля.
  2. Когда родительский процесс завершается, дочерние процессы не получают никакого сигнала, потому что PR_SET_PDEATHSIG атрибут в prctl () сбрасывается.
  3. Поток, используемый для вызова fork (), создает дочерний процесс. Таким образом, адрес дочернего процесса будет таким же, как и у родительского.
  4. Файловый дескриптор родительского процесса наследуется дочерним процессом. Например, смещение файла или состояние флагов и атрибутов ввода-вывода будут совместно использоваться дескрипторами файлов дочерних и родительских процессов. Таким образом, файловый дескриптор родительского класса будет ссылаться на тот же файловый дескриптор дочернего класса.
  5. Дескрипторы открытой очереди сообщений родительского процесса наследуются дочерним процессом. Например, если файловый дескриптор содержит сообщение в родительском процессе, то же сообщение будет присутствовать в соответствующем файловом дескрипторе дочернего процесса. Таким образом, мы можем сказать, что значения флагов этих файловых дескрипторов одинаковы.
  6. Аналогичным образом потоки открытых каталогов будут унаследованы дочерними процессами.
  7. Значение задержки таймера по умолчанию дочернего класса совпадает с текущим значением задержки таймера родительского класса.

Свойства, которые не наследуются дочерним процессом

Ниже приведены некоторые свойств, которые не наследуются дочерним процессом:

  1. Блокировки памяти
  2. Ожидающий сигнал дочернего класса пуст.
  3. Обработка связанных блокировок записей (fcntl ())
  4. Асинхронные операции ввода-вывода и содержимое ввода-вывода.
  5. Уведомления об изменении каталога.
  6. Таймеры, такие как alarm (), setitimer (), не наследуются дочерним классом.

fork () в C

В fork () нет аргументов, а тип возвращаемого значения fork () — целое число.. При использовании fork () необходимо включить следующие файлы заголовков:

#include
#include
#include

При работе с fork () может использоваться для типа pid_t для идентификаторов процессов, поскольку pid_t определен в .

Заголовочный файл — это то место, где fork ( ) определен, поэтому вы должны включить его в свою программу для использования fork ().

Тип возвращаемого значения определен в , а вызов fork () определен в . Следовательно, вам необходимо включить оба в свою программу, чтобы использовать системный вызов fork ().

Синтаксис fork ()

Синтаксис системного вызова fork () в Linux, Ubuntu выглядит следующим образом:

pid_t fork (void);

В синтаксисе тип возврата — pid_t . Когда дочерний процесс успешно создан, PID дочернего процесса возвращается в родительском процессе, и 0 будет возвращен самому дочернему процессу.

Если есть какая-либо ошибка, возвращается -1 родительскому процессу, а дочерний процесс не создается.

 В fork () не передаются аргументы. 

Пример 1: Вызов fork ()

Рассмотрим следующий пример, в котором мы использовали системный вызов fork () для создания нового дочернего процесса:

CODE:

#include
#include
#include

int main ()
{
fork ();
printf («Использование системного вызова fork () n»);
return 0;
}

Использование системного вызова fork ()
Использование системного вызова fork ()

В этой программе мы использовали fork (), это создаст новый дочерний процесс. При создании дочернего процесса и родительский, и дочерний процессы будут указывать на следующую инструкцию (тот же программный счетчик). Таким образом, оставшиеся инструкции или операторы C будут выполняться общее количество раз процесса, то есть 2 n раз, где n — количество системных вызовов fork ().

Итак, когда вызов fork () используется один раз, как указано выше (2 1 = 2), мы получим наш результат 2 раза.

Здесь, когда используется системный вызов fork (), внутренняя структура будет выглядеть так:

Рассмотрим следующий случай, в котором fork () используется 4 раза:

КОД:

#include
#include
#include

int main ()
{
fork ();
fork ();
fork ();
fork ();
printf («Использование системного вызова fork ()»);
return 0;
}

Вывод:

 Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование fork (  Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование системного вызова fork () Использование fork (  ) системный вызов 

Теперь общее количество созданных процессов 2 4 = 16, и мы выполнили нашу инструкцию print 16 раз.

Пример 2: Проверка успешности fork ()

В следующем примере мы использовали конструкцию принятия решения для проверки значения (int), возвращаемого функцией fork (). И отображаются соответствующие сообщения:

CODE:

#include
#include
#include

int main ()
{
pid_t p;
p = fork ();
if (p == — 1)
{
printf («Ошибка при вызове fork ()» );
}
if (p == 0)
{
printf («Мы находимся в дочернем процессе»);
}
else
{
printf («Мы находимся в родительском процессе»);
}
return 0;
}

ВЫХОД:

Мы находимся в родительском процессе
Мы находимся в дочерний процесс

В приведенном выше примере мы использовали тип pid_t, который будет хранить возвращаемое значение fork (). fork () вызывается в строке:

p = fork ();

Итак, целочисленное значение, возвращаемое fork () хранится в p, а затем p сравнивается, чтобы проверить, был ли наш вызов fork () успешным.

Когда используется вызов fork () и дочерний процесс создается успешно, идентификатор дочернего процесса будет возвращается родительскому процессу, а дочернему процессу будет возвращено 0. Идентификатор дочернего процесса в родительском процессе не будет таким же, как идентификатор дочернего процесса в самом дочернем процессе. В дочернем процессе идентификатор дочернего процесса будет 0.

Из этого руководства вы узнаете, как начать работу с системным вызовом fork в Linux.

Оцените статью
nanomode.ru
Добавить комментарий