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

Fork System Call 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 () необходимо включить следующие файлы заголовков:



#включают
#включают
#включают

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

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

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

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

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

pid_t fork (пусто);

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

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

No arguments are passed to fork(). 

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

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

КОД:

#включают
#включают
#включают

intглавный()
{
вилка();
printf ('Использование системного вызова fork () п');
возвращение 0;
}

ВЫХОД:

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

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

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

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

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

КОД:

#включают
#включают
#включают

intглавный()
{
вилка();
вилка();
вилка();
вилка();
printf ('Использование системного вызова fork ()');
возвращение 0;
}

Выход:

Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call 

Теперь общее количество созданных процессов равно 2.4= 16, и наш оператор печати выполняется 16 раз.

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

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

КОД:

#включают
#включают
#включают

intглавный()
{
pid_t p;
пзнак равновилка();
если(п== -1)
{
printf ('Ошибка при вызове fork ()');
}
если(п==0)
{
printf ('Мы находимся в дочернем процессе');
}
еще
{
printf ('Мы находимся в родительском процессе');
}
возвращение 0;
}

ВЫХОД:

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

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

пзнак равновилка();

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

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

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