ОБЗОР
#include <unistd.h>pid_t fork(void);
ОПИСАНИЕ
Вызов fork() создаёт новый процесс посредством копирования вызывающего процесса. Новый процесс считается дочерним процессом. Вызывающий процесс считается родительским процессом.Дочерний и родительский процессы находятся в отдельных пространствах памяти. Сразу после fork() эти пространства имеют одинаковое содержимое. Запись в память, отображение файлов (mmap(2)) и снятие отображения (munmap(2)), выполненных в одном процессе, ничего не изменяет в другом.
Дочерний процесс является точной копией родительского процесса за исключением следующих моментов:
- *
- Потомок имеет свой уникальный идентификатор процесса, и этот PID (идентификатор процесса) не совпадает ни с одним существующим идентификатором группы процессов (setpgid(2)).
- *
- Идентификатор родительского процесса у потомка равен идентификатору родительского процесса.
- *
- Потомок не наследует блокировки памяти родителя (mlock(2), mlockall(2)).
- *
- Счётчики использования ресурсов (getrusage(2)) и времени ЦП у потомка сброшены в 0.
- *
- Набор ожидающих сигналов потомка изначально пуст (sigpending(2)).
- *
- Потомок не наследует значения семафоров родителя (semop(2)).
- *
- Потомок не наследует связанные с процессом блокировки родителя (fcntl(2)) (с другой стороны, он наследует блокировки файловых описаний fcntl(2) и блокировки flock(2)).
- *
- Потомок не наследует таймеры родителя (setitimer(2), alarm(2), timer_create(2)).
- *
- Потомок не наследует ожидающие выполнения операции асинхронного ввода-вывода (aio_read(3), aio_write(3)) и контексты асинхронного ввода-вывода родителя (см. io_setup(2)).
Все перечисленные атрибуты указаны в POSIX.1. Родитель и потомок также отличаются по следующим атрибутам процесса, которые есть только в Linux:
- *
- Потомок не наследует уведомления об изменении каталога (dnotify) родителя (смотрите описание F_NOTIFY в fcntl(2)).
- *
- Настройка PR_SET_PDEATHSIG у prctl(2) сбрасывается, и поэтому потомок не принимает сигнал о завершении работы родителя.
- *
- Резервное значение по умолчанию устанавливается равным родительскому текущему резервному значению таймера. Смотрите описание PR_SET_TIMERSLACK в prctl(2).
- *
- Отображение памяти, помеченное с помощью флага MADV_DONTFORK через madvise(2), при fork() не наследуется.
- *
- Сигнал завершения работы потомка всегда SIGCHLD (см. clone(2)).
- *
- Биты прав доступа к порту, установленные с помощью ioperm(2), не наследуются потомком; потомок должен установить все нужные ему биты с помощью ioperm(2).
Также стоит учитывать следующее:
- *
- Процесс потомка создаётся с одиночной нитью — той, которая вызвала fork(). Всё виртуальное адресное пространство родителя копируется в потомок, включая состояние мьютексов, условных переменных и других объектов pthreads; в случае проблем с этим может помочь pthread_atfork(3).
- *
- В многонитивой программе после fork(2) потомок может безопасно вызывать только безопасные-асинхронные-сигнальные функции (смотрите signal(7)) до тех пор, пока не вызовет execve(2).
- *
- Потомок наследует копии набора открытых файловых дескрипторов родителя. Каждый файловый дескриптор в потомке ссылается на то же описание файла что и родитель (смотрите open(2)). Это означает, что два файловых дескриптора совместно используют флаги состояния открытого файла, текущее смещение файла и атрибуты ввода-вывода, управляемые сигналами (смотрите описание F_SETOWN и F_SETSIG в fcntl(2)).
- *
- Потомок наследует копии набора файловых дескрипторов открытых очередей сообщений родителя (смотрите mq_overview(7)). Каждый файловый дескриптор в потомке ссылается на то же описание открытой очереди сообщений что и родитель. Это означает, что два файловых дескриптора совместно используют флаги (mq_flags).
- *
- Потомок наследует копии набора потоков открытых каталогов родителя (смотрите opendir(3)). В POSIX.1 сказано, что соответствующие потоки каталогов в родителе и потомке могут совместно использовать позицию в потоке каталога; в Linux/glibc они не могут этого делать.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном завершении родителю возвращается PID процесса-потомка, а процессу-потомку возвращается 0. При ошибке родительскому процессу возвращается -1, процесс-потомок не создаётся, а значение errno устанавливается в соответствующее значение.ОШИБКИ
- EAGAIN
-
Возникло системного ограничение на количество нитей. Есть несколько ограничений, которые могут вызвать эту ошибку: был достигнут мягкий ограничитель RLIMIT_NPROC (задаётся с помощью setrlimit(2)), который ограничивает количество процессов и ните для реального ID пользователя; был достигнут ядерный системный ограничитель на количество процессов и нитей, /proc/sys/kernel/threads-max (смотрите proc(5)); был достигнуто максимальное количество PID, /proc/sys/kernel/pid_max (смотрите proc(5)).
- EAGAIN
- Вызывающий работает по алгоритму планирования SCHED_DEADLINE и у него не установлен флаг сброса-при-fork (reset-on-fork). Смотрите sched(7).
- ENOMEM
- Вызов fork() завершился с ошибкой из-за невозможности разместить необходимые структуры ядра, потому что слишком мало памяти.
- ENOSYS
- Вызов fork() не поддерживается на этой платформе (например, из-за того, что аппаратное обеспечение не содержит блока управления памятью (MMU)).
СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.ЗАМЕЧАНИЯ
В Linux, fork() реализован с помощью «копирования страниц при записи» (copy-on-write, COW), поэтому расходы на вызов состоят из времени и памяти, требуемой на копирование страничных таблиц родителя и создания уникальной структуры, описывающей задачу.