Концепции операционной системы и APUE говорят
При использовании vfork () родительский процесс приостанавливается, а дочерний процесс использует адресное пространство родительского процесса. Поскольку vfork () не использует копирование при записи, если дочерний процесс изменяет какие-либо страницы адресного пространства родителя, измененные страницы будут видны родителю после его возобновления. Поэтому vfork () следует использовать с осторожностью, чтобы дочерний процесс не изменял адресное пространство родительского процесса.
vfork () предназначен для использования, когда дочерний процесс вызывает exec () или exit () сразу после создания.
Как я пойму последнее предложение?
Когда дочерний процесс, созданный vfork()
вызовами exec()
, не exec()
изменяет адресное пространство родительского процесса, загружая новую программу?
Когда дочерний процесс создается vfork()
вызовами exit()
, exit()
не изменяется ли адресное пространство родительского процесса при завершении дочернего процесса?
У меня есть предпочтение Linux.
Спасибо.
posix_spawn
. Писать правильный код значительно сложнее,posix_spawn
чем при использовании старогоfork
, и, если вы попробуете, вы можете столкнуться с кирпичной стеной, где нет файлового действия или атрибута, который делает то, что вам нужно сделать междуfork
иexec
. И это не гарантирует эффективность, подобную vfork, поэтому она даже не решает проблему, которую люди хотят решить.posix_spawn
может не хватать нужной вам функциональности (вы можете решить эту проблему с помощью промежуточной вспомогательной программы, написанной на языке C или сценарием оболочки inline-on-cmdline), любая попытка достичь желаемого с помощьюvfork
вызывает опасное неопределенное поведение. Спецификация forvfork
не позволяет вызывать случайные функции для установки состояния, которое дочерний элемент должен наследовать ранееexecve
, и попытки сделать это могут повредить состояние родительского элемента.posix_spawn
работает примерно так же, какvfork
в большинстве условий. Те, где есть различие, как правило, являются именно теми случаями, когдаvfork
это крайне небезопасно: где установлены обработчики сигналов, которыеposix_spawn
должны препятствовать запуску в дочернем процессе до выполнения exec.Когда вы вызываете
vfork()
, создается новый процесс, и этот новый процесс заимствует образ процесса родительского процесса, за исключением стека. Дочернему процессу присваивается собственная новая звезда стека, однако он не допускаетсяreturn
из вызывающей функцииvfork()
.Пока дочерний процесс выполняется, родительский процесс блокируется, поскольку дочерний процесс занял адресное пространство родительского процесса.
Независимо от того, что вы делаете, все, что просто обращается к стеку, изменяет только частный стек дочернего элемента. Однако если вы изменяете глобальные данные, это изменяет общие данные и, таким образом, также влияет на родительские данные.
Вещи, которые изменяют глобальные данные, например:
вызов malloc () или free ()
используя stdio
изменение настроек сигнала
изменение переменных, которые не являются локальными для вызывающей функции
vfork()
....
Когда вы звоните
_exit()
(важно, никогда не звонитеexit()
), дочерний процесс прекращается, и контроль возвращается родителю.Если вы вызываете какую-либо функцию из
exec*()
семейства, создается новое адресное пространство с новым программным кодом, новыми данными и частью стека от родительского (см. Ниже). Как только это будет готово, дочерний элемент больше не заимствует адресное пространство у дочернего элемента, а использует собственное адресное пространство.Элемент управления возвращается родителю, так как его адресное пространство больше не используется другим процессом.
Важно: в Linux нет реальной
vfork()
реализации. Linux, скорее, реализуетvfork()
на основеfork()
концепции «Копировать при записи», введенной SunOS-4.0 в 1988 году. Чтобы заставить пользователей поверить, что они используютvfork()
, Linux просто устанавливает общие данные и приостанавливает родительский процесс, пока ребенок не вызвал_exit()
или одну изexec*()
функций.Поэтому Linux не извлекает выгоду из того факта, что реальному
vfork()
не нужно устанавливать описание адресного пространства для дочернего элемента в ядре. Это приводит к тому,vfork()
что это не быстрее, чемfork()
. В системах, которые реализуют реальныйvfork()
, он обычно в 3 раза быстрееfork()
и влияет на производительность используемых оболочекvfork()
-ksh93
, последнихBourne Shell
иcsh
.Причина, по которой вы никогда не должны звонить
exit()
отvfork()
дочернегоexit()
элемента ed, заключается в том, что сбрасывает stdio в случае, если за время до вызова были получены незаполненные данныеvfork()
. Это может привести к странным результатам.Кстати:
posix_spawn()
реализован поверхvfork()
, поэтомуvfork()
не будет удален из ОС. Было упомянуто, что Linux не используетvfork()
дляposix_spawn()
.Что касается стека, документации мало, вот что написано на странице руководства Solaris:
Так что реализация может делать все что угодно. Реализация Solaris использует общую память для стекового фрейма вызова функции
vfork()
. Ни одна реализация не предоставляет доступ к более старым частям стека от родительского.источник
posix_spawn()
поверх Linuxvfork()
. Они оба реализуют это сверху__clone()
.vfork()
просто звонитclone()
правильно? Это буквально однострочно в ядре.vfork
иfork
Linux, значит, он делает что-то не так.