Из расширенного программирования в среде UNIX У. Ричарда Стивенса (стр. 188):
8.3 функция fork
Единственный способ создания нового процесса ядром Unix - это когда существующий процесс вызывает функцию fork
. (Это не относится к специальным процессам, которые мы упоминали в предыдущем разделе - swapper, init
и pagedaemon. Эти процессы специально создаются ядром как часть начальной загрузки.)
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
/* Returns: 0 in child, process ID of child in parent, -1 on error */
Новый процесс, созданный fork
, называется дочерним процессом . Функция вызывается один раз, но возвращается дважды. Единственная разница в возвращаемых значениях заключается в том, что возвращаемое значение в дочернем элементе равно 0, а возвращаемое значение в родительском элементе является идентификатором процесса нового дочернего элемента. Причина, по которой идентификатор дочернего процесса возвращается родителю, состоит в том, что у процесса может быть более одного дочернего элемента, поэтому нет функции, которая позволяла бы процессу получать идентификаторы процессов своих дочерних элементов. Причина, по которой fork
возвращает 0 дочернему элементу, заключается в том, что у процесса может быть только один родительский элемент, поэтому дочерний элемент всегда может вызвать getppid
для получения идентификатора процесса своего родительского элемента. (Идентификатор процесса 0 всегда используется подкачкой, поэтому 0 не может быть идентификатором процесса дочернего элемента.)
И ребенок, и родитель продолжают выполнение с инструкцией, следующей за вызовом fork
. Ребенок является копией родителя. Например, потомок получает копию пространства данных, кучи и стека родителя. Обратите внимание, что это копия для дочернего элемента - родитель и дочерний элемент не разделяют эти части памяти. Часто родитель и потомок разделяют текстовый сегмент (раздел 7.6), если он доступен только для чтения.
В Linux оператор fork
Perl вызывает системную fork
и возвращает undef
при ошибке, а не -1.
Стивенс приводит списки (стр. 192) наследуемых свойств и различий между родительскими процессами и их раздвоенными детьми:
Помимо открытых файлов, существует множество других свойств родителя, которые наследуются дочерним элементом:
- реальный идентификатор пользователя, реальный идентификатор группы, эффективный идентификатор пользователя, эффективный идентификатор группы
- идентификаторы дополнительных групп
- ID группы процессов
- идентификатор сессии
- управляющий терминал
- флаг set-user-ID и флаг set-group-ID
- текущий рабочий каталог
- корневая директория
- маска создания режима файла
- сигнальная маска и диспозиции
- флаг close-on-exec для любых открытых файловых дескрипторов
- среда
- прикрепленные сегменты общей памяти
- пределы ресурса
Различия между родителем и ребенком
- возвращаемое значение из
fork
- идентификаторы процессов разные
- два процесса имеют разные идентификаторы родительских процессов - родительский идентификатор родительского процесса; идентификатор родительского процесса не меняется
- значения потомков для
tms_utime
, tms_stime
, tms_cutime
и tms_ustime
установлены в 0
- блокировки файлов, установленные родителем, не наследуются дочерним
- ожидающие тревоги очищаются для ребенка
- набор ожидающих сигналов для ребенка устанавливается в пустой набор