Почему по умолчанию используется механизм создания процесса fork?

46

Системный вызов UNIX для создания процесса, fork (), создает дочерний процесс путем копирования родительского процесса. Насколько я понимаю, за этим почти всегда следует вызов exec () для замены пространства памяти дочернего процесса (включая текстовый сегмент). Копирование пространства памяти родителя в fork () всегда казалось мне расточительным (хотя я понимаю, что отходы можно минимизировать, копируя при записи сегменты памяти, чтобы копировались только указатели). Во всяком случае, кто-нибудь знает, почему этот подход дублирования требуется для создания процесса?

Эллен Спертус
источник
3
Обратите внимание, что на fork(2)странице руководства под Linux написано: « Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. Я представляю (но не знаю наверняка), что это имеет место для других современных разновидностей Unix.
Жаворонки
4
Оригинальный, PDP-11 Unix действительно, действительно копировал все байты разветвленного процесса: но он имел только 64 КБ исполняемого файла и не более 64 КБ данных, так что это не было огромной нагрузкой даже в 1975 году. Предположим, что КАЖДЫЙ unix и unix-a-like, начиная с 1990 года, имели текстовые сегменты с копированием при записи, поэтому я даже не уверен, почему книги и статьи распространяют «проблему производительности с fork».
Брюс Эдигер
В настоящее время fork реализован аналогично vfork ( openbsd.org/cgi-bin/… ). Это эффективно, не волнуйтесь.
Аки
Также обратите внимание, что во многих случаях вы не используете exec после разветвления (или, по крайней мере, не сразу): вспомните о каналах и веб-серверах.
jfg956
Вы можете что-то сделать медленно. Но, как говорит @cjm, посмотрите на альтернативу, которую Microsoft использует CreateProcess, им пришлось внедрять потоки на раннем этапе (возможно, это единственное, на что они ведут), потому что CreateProcess медленный. (Им тоже нужны были темы, потому что selectбыл сломан, но это уже другая история).
Ctrl-Alt-Delor

Ответы:

57

Это для упрощения интерфейса. Альтернативой forkи execбудет что-то вроде функции Windows CreateProcess . Обратите внимание, сколько параметров CreateProcessимеет, и многие из них являются структурами с еще большим количеством параметров. Это потому, что все, что вы можете контролировать в новом процессе, должно быть передано CreateProcess. На самом деле CreateProcessне хватает параметров, поэтому Microsoft пришлось добавить CreateProcessAsUser и CreateProcessWithLogonW .

С fork/execмоделью вам не нужны все эти параметры. Вместо этого определенные атрибуты процесса сохраняются exec. Это позволяет вам forkзатем изменить любые атрибуты процесса, которые вы хотите (используя те же функции, которые вы обычно используете), а затем exec . В Linux forkне имеет параметров и execveимеет только 3: программу для запуска, командную строку для ее выдачи и ее среду. (Существуют и другие execфункции, но они являются просто обертками, execveпредоставляемыми библиотекой C, для упрощения общих случаев использования.)

Если вы хотите , чтобы начать процесс с другим текущим каталогом: fork, chdir, exec.

Если вы хотите Перенаправление STDIN / STDOUT: fork, закрытие / открытые файлы, exec.

Если вы хотите , чтобы пользователи переключателя: fork, setuid, exec.

Все эти вещи могут быть объединены по мере необходимости. Если кто-то придумает новый тип атрибута процесса, вам не нужно менять forkи exec.

Как уже упоминалось, большинство современных Unix-систем используют копирование при записи, поэтому forkне требует значительных накладных расходов.

CJM
источник
16
Отличное объяснение. «Те, кто не понимает UNIX, обречены плохо его изобретать». - Генри Спенсер
Кайл Джонс
1
Спасибо! У вас есть ссылка, случайно?
Эллен Спертус
1
@Aki, нет, CreateProcess () буквально создает новый процесс и создает его с нуля, без разветвления.
psusi
2
Но разве в Unix не должно быть какого-либо эквивалента CreateProcess ()? Иначе как создается самый первый процесс? В отличие от мифологического бога-создателя, первый процесс не может разветвляться () из ничего. ;-)
Стивен Понедельник
2
@StevenMonday, да, но он находится в коде инициализации ядра и не доступен извне. Ему не нужны все эти параметры, потому что почти все жестко закодировано. Он может только создать процесс с идентификатором 1, он же процесс init. После этого процессы создаются только путем разветвления.
CJM
5

В дополнение к ответу cjm, Спецификация Single Unix определяет функцию с именем vfork(). Эта функция работает как fork, за исключением того, что разветвленный процесс имеет неопределенное поведение, если он делает что-то кроме попыток вызова функции exec familly или вызова _exit().

Таким образом, почти единственное использование с определенным поведением:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

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

Существует также дополнительная posix_spawnфункция (и posix_spawnpфункция), которая может непосредственно создавать новый процесс. (Также допустимо реализовать их с помощью вызова библиотеки с использованием forkи exec, и приведен пример реализации.)

Кевин Кэткарт
источник