Подтвердить что ты не робот

В чем разница между fork() и vfork()?

В чем разница между fork() и vfork()? Возвращает ли vfork() как fork().

4b9b3361

Ответ 1

Цель vfork заключалась в том, чтобы устранить накладные расходы на копирование всего образа процесса, если вы хотите сделать только exec* в дочернем элементе. Поскольку exec* заменяет весь образ дочернего процесса, нет смысла копировать изображение родителя.

if ((pid = vfork()) == 0) {
  execl(..., NULL); /* after a successful execl the parent should be resumed */
  _exit(127); /* terminate the child in case execl fails */
}

Для других видов использования vfork является опасным и непредсказуемым.

Однако при использовании большинства современных ядер, включая Linux, основное преимущество vfork исчезло из-за реализации fork. Вместо копирования всего изображения при выполнении fork используются методы копирования на запись.

Ответ 2

Как уже говорилось, справочная страница vfork понятна о различиях. Эта тема дает хорошее описание fork, vfork, clone и exec.

Ниже приведены некоторые часто упущенные различия между fork и vfork, которые я испытывал в некоторых встроенных системах Linux 2.6.3x, с которыми я работал.

Даже при использовании методов copy-on-write fork завершается сбой, если у вас недостаточно памяти для дублирования памяти, используемой родительским процессом. Например, если родительский процесс использует 2 ГБ резидентной памяти (т.е. Память, которая используется, а не только выделена), fork терпит неудачу, если у вас осталось менее 2 ГБ свободной памяти. Это расстраивает, когда вы просто хотите exec простую программу и поэтому никогда не будете нуждаться в этом огромном адресном пространстве родителя!

vfork не имеет этой проблемы с памятью, поскольку она не дублирует родительское адресное пространство. Детский процесс больше похож на поток, в котором вы можете вызвать exec* или _exit, не повреждая родительский процесс.

Поскольку таблицы страниц памяти не дублируются, vfork намного быстрее, чем fork и vfork время выполнения не зависит от объема памяти, которую использует родительский процесс, как указано здесь: http://blog.famzah.net/2009/11/20/fork-gets-slower-as-parent-process-use-more-memory/

В ситуациях, когда производительность критическая и/или ограниченная память, vfork + exec* может быть хорошей альтернативой fork + exec*. Проблема в том, что она менее безопасна, и в man-странице говорится, что vfork, скорее всего, устареет в будущем.

Более безопасным и более портативным решением может быть просмотр функции posix_spawn, которая является более высоким уровнем и предлагает больше возможностей. Он безопасно использует vfork, когда это возможно, в зависимости от параметров, которые вы передаете. Я смог успешно использовать posix_spawn и преодолеть эту досадную проблему с двойной памятью, которую мне дала fork + exec.

Действительно хорошая страница по этой теме со ссылками на некоторые примеры posix_spawn.

Ответ 3

Из моей страницы man

(из POSIX.1) Функция vfork() имеет тот же эффект, что и fork (2), за исключением что поведение undefined, если процесс, созданный        vfork() либо изменяет любые данные, отличные от переменной типа pid_t используется для хранения возвращаемого значения из vfork() или возвращает из        функция, в которой был вызван vfork(), или вызывает любую другую функцию перед успешным вызовом _exit (2) или одного из семейства exec (3)        функции.

vfork() отличается от fork (2) в что родитель приостанавливается до тех пор, пока ребенок заканчивается (как обычно, вызов _exit (2) или        ненормально, после доставки фатального сигнала), или он обращается к execve (2). До этого момента ребенок разделяет всю память с        его родитель, включая стек. Ребенок не должен возвращаться из текущая функция или выход вызова (3), но может вызвать _exit (2).

Ответ 4

В некоторых системах есть системный вызов vfork(), который изначально был разработан как более низкая служебная версия fork(). Поскольку fork() включал копирование всего адресного пространства процесса, и поэтому было довольно дорого, была введена функция vfork() (в версии 3.0BSD).

Однако, поскольку vfork() был введен, реализация fork() значительно улучшилась, особенно с введением "copy-on-write", где копирование адресного пространства процесса прозрачно подделано, позволяя как процессов, чтобы ссылаться на одну и ту же физическую память, пока один из них не изменит ее. Это в значительной степени устраняет обоснование для vfork(); действительно, большая часть систем в настоящее время не имеет первоначальной функциональности vfork() полностью. Тем не менее, для совместимости все еще может присутствовать вызов vfork(), который просто вызывает fork(), не пытаясь подражать всей семантике vfork().

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

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

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

Ответ 5

Обратитесь здесь и wikipedia -

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

Ответ 6

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

Это означает, что дочерний процесс vfork() должен быть осторожен избегать непредвиденных изменений переменных родительского процесса. В в частности, дочерний процесс не должен возвращаться из функции содержащий вызов vfork(), и он не должен звонить exit() (если нужно выйти, он должен использовать _exit(); на самом деле это также верно для ребенка нормального fork()).

Однако, поскольку vfork() было введено, реализация fork() значительно улучшилась, особенно с введением "copy-on-write", , где копирование адресное пространство процесса прозрачно подделано, разрешая оба процесса для обращения к той же физической памяти, пока ни один из них не изменит это. Это в значительной степени устраняет оправдание vfork();, действительно, большая часть систем теперь не имеет исходной функциональности vfork() полностью. Однако для совместимости все еще может быть a vfork(), который просто вызывает fork() без пытаясь подражать всей семантике vfork().

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