fork - создаёт
дочерний
процесс
Standard C library (
libc,
-lc)
#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() не
наследуется.
- •
- Память в
диапазонах
адресов,
которые
были
помечены с
помощью madvise(2)
флагом MADV_WIPEONFORK,
обнуляются
в потомке
после fork()
(флаг MADV_WIPEONFORK
остаётся в
потомке у
этих
диапазонов
адресов).
- •
- Сигнал
завершения
работы
потомка
всегда SIGCHLD
(см. clone(2)).
- •
- Биты
прав
доступа к
порту,
установленные
с помощью
ioperm(2), не
наследуются
потомком;
потомок
должен
установить
все нужные
ему биты с
помощью
ioperm(2).
Также
стоит
учитывать
следующее:
- •
- The child process is created with a single
thread—the one that called fork(). The entire virtual
address space of the parent is replicated in the child, including the
states of mutexes, condition variables, and other pthreads objects; the
use of pthread_atfork(3) may be helpful for dealing with problems
that this can cause.
- •
- В
многонитевой
программе
после fork()
потомок
может
безопасно
вызывать
только
безопасные-асинхронные-сигнальные
функции
(смотрите
signal-safety(7)) до тех
пор, пока
не вызовет
execve(2).
- •
- Потомок
наследует
копии
набора
открытых
файловых
дескрипторов
родителя.
Каждый
файловый
дескриптор
в потомке
ссылается
на то же
описание
файла что и
родитель
(смотрите
open(2)). Это
означает,
что два
файловых
дескриптора
совместно
используют
флаги
состояния
открытого
файла,
смещение
файла и
атрибуты
ввода-вывода,
управляемые
сигналами
(смотрите
описание
F_SETOWN и F_SETSIG в fcntl(2)).
- •
- Потомок
наследует
копии
набора
файловых
дескрипторов
открытых
очередей
сообщений
родителя
(смотрите
mq_overview(7)). Каждый
файловый
дескриптор
в потомке
ссылается
на то же
описание
открытой
очереди
сообщений
что и
родитель.
Это
означает,
что два
файловых
дескриптора
совместно
используют
флаги ( mq_flags).
- •
- Потомок
наследует
копии
набора
потоков
открытых
каталогов
родителя
(смотрите
opendir(3)). В POSIX.1
сказано,
что
соответствующие
потоки
каталогов
в родителе
и потомке
могут
совместно
использовать
позицию в
потоке
каталога; в
Linux/glibc они не
могут
этого
делать.
On success, the PID of the child process is returned in the parent, and 0 is
returned in the child. On failure, -1 is returned in the parent, no child
process is created, and
errno is set to indicate the error.
- EAGAIN
- Возникло
системного
ограничение
на
количество
нитей. Есть
несколько
ограничений,
которые
могут
вызвать
эту
ошибку:
- •
-
RLIMIT_NPROC
(задаётся с
помощью
setrlimit(2)),
который
ограничивает
количество
процессов
и ните для
реального
ID
пользователя;
- •
- было
достигнуто
системное
ограничение
ядра на
количество
процессов
и нитей,
/proc/sys/kernel/threads-max
(смотрите
proc(5));
- •
- достигнуто
максимальное
количество
PID, /proc/sys/kernel/pid_max
(смотрите
proc(5)); или
- •
- достигнуто
ограничение
на PID ( pids.max),
наложенное
контроллером
cgroup на «номер
процесса»
(PID).
- EAGAIN
- Вызывающий
работает
по
алгоритму
планирования
SCHED_DEADLINE и у него
не
установлен
флаг
сброса-при-fork
(reset-on-fork).
Смотрите
sched(7).
- ENOMEM
- Вызов fork()
завершился
с ошибкой
из-за
невозможности
разместить
необходимые
структуры
ядра,
потому что
слишком
мало
памяти.
- ENOMEM
- Была
попытка
создания
дочерний
процесс в
пространстве
имён PID, чей
процесс
«init»
завершил
работу.
Смотрите
pid_namespaces(7).
- ENOSYS
- Вызов fork()
не
поддерживается
на этой
платформе
(например,
из-за того,
что
аппаратное
обеспечение
не
содержит
блока
управления
памятью (MMU)).
-
ERESTARTNOINTR
(начиная с Linux
2.6.17)
- Системный
вызов был
прерван
сигналом и
перезапущен
(может быть
замечено
только при
трассировке).
POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.
В Linux,
fork()
реализован
с помощью
«копирования
страниц
при
записи» (copy-on-write, COW),
поэтому
расходы на
вызов
состоят из
времени и
памяти,
требуемой
на
копирование
страничных
таблиц
родителя и
создания
уникальной
структуры,
описывающей
задачу.
Since glibc 2.3.3, rather than invoking the kernel's
fork() system call,
the glibc
fork() wrapper that is provided as part of the NPTL threading
implementation invokes
clone(2) with flags that provide the same effect
as the traditional system call. (A call to
fork() is equivalent to a
call to
clone(2) specifying
flags as just
SIGCHLD.) The
glibc wrapper invokes any fork handlers that have been established using
pthread_atfork(3).
See
pipe(2) and
wait(2) for more examples.
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(void)
{
pid_t pid;
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
perror("signal");
exit(EXIT_FAILURE);
}
pid = fork();
switch (pid) {
case -1:
perror("fork");
exit(EXIT_FAILURE);
case 0:
puts("Child exiting.");
exit(EXIT_SUCCESS);
default:
printf("Child is PID %jd\n", (intmax_t) pid);
puts("Parent exiting.");
exit(EXIT_SUCCESS);
}
}
clone(2),
execve(2),
exit(2),
setrlimit(2),
unshare(2),
vfork(2),
wait(2),
daemon(3),
pthread_atfork(3),
capabilities(7),
credentials(7)
Русский
перевод
этой
страницы
руководства
был сделан
Azamat Hackimov <
[email protected]>, Dmitry Bolkhovskikh
<
[email protected]>, Yuri Kozlov <
[email protected]> и
Иван
Павлов <
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]