Главная » 2017 » Ноябрь » 17 » man 2 fork
01:50
man 2 fork

SEO sprint - Всё для максимальной раскрутки!





ИМЯ


fork - создаёт дочерний процесс



ОБЗОР


#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) сбрасывается, и поэтому потомок не
принимает сигнал о завершении работы родителя.

потомком; потомок должен установить все нужные ему биты с помощью ioperm(2).

Также стоит учитывать следующее:

* Процесс потомка создаётся с одиночной нитью — той, которая вызвала fork(). Всё
виртуальное адресное пространство родителя копируется в потомок, включая
состояние мьютексов, условных переменных и других объектов pthreads; в случае
проблем с этим может помочь pthread_atfork(3).

* В многонитивой программе после fork() потомок может безопасно вызывать только
безопасные-асинхронные-сигнальные функции (смотрите 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() завершился с ошибкой из-за невозможности разместить
необходимые структуры ядра, потому что слишком мало памяти.

ENOMEM Была попытка создания дочерний процесс в пространстве имён PID, чей процесс
«init» завершил работу. Смотрите pid_namespaces(7).

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

В Linux, fork() реализован с помощью «копирования страниц при записи»
(copy-on-write, COW), поэтому расходы на вызов состоят из времени и памяти,
требуемой на копирование страничных таблиц родителя и создания уникальной
структуры, описывающей задачу.

Отличия между библиотекой C и ядром
Начиная с версии 2.3.3, вместо того, чтобы вызывать системный вызов fork(),
обёрточная функция fork() в glibc, как часть реализации нитей NPTL, вызывает
clone(2) с флагами, которые обеспечивают поведение традиционного системного вызова
(вызов fork() эквивалентен вызову clone(2), если значение равно flags SIGCHLD).
Обёртка в glibc вызывает все обработчики при ветвлении (fork), которые были
зарегистрированы с помощью pthread_atfork(3).



ПРИМЕР


Смотрите pipe(2) и wait(2).



СМОТРИТЕ ТАКЖЕ


clone(2), execve(2), exit(2), setrlimit(2), unshare(2), vfork(2), wait(2),
daemon(3), capabilities(7), credentials(7)



Категория: (2) Системные вызовы ядра (функции языка Си) | Просмотров: 560 | Добавил: Администратор | Рейтинг: 0.0/0
Всего комментариев: 0
avatar