В чем разница между fork () и vfork ()? - PullRequest
31 голосов
/ 23 ноября 2010

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

Ответы [ 6 ]

35 голосов
/ 23 ноября 2010

Цель 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 используются методы копирования при записи.

23 голосов
/ 06 марта 2011

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

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

Даже при использовании методов копирования при записи 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*. Проблема в том, что он менее безопасен, а на странице руководства написано, что vfork в будущем, скорее всего, устареет.

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

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

4 голосов
/ 23 ноября 2010

Из моей справочной страницы

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

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

2 голосов
/ 26 декабря 2013

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

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

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

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

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

1 голос
/ 28 марта 2015

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

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

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

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

1 голос
/ 23 ноября 2010

См. здесь и википедии -

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

...