Я пытался найти разницу между этими четырьмя в Google, и я ожидал, что по этому поводу будет огромное количество информации, но между четырьмя звонками действительно не было четкого сравнения.
Я попытался скомпилировать некий базовый взгляд на различия между этими системными вызовами и вот что я получил. Вся эта информация верна / я что-то упускаю?
Fork
Вызов fork в основном создает дубликаты текущего процесса, практически идентичные (не все копируются, например, из-за ограничений ресурсов в некоторых реализациях, но идея состоит в том, чтобы создать максимально близкую копию).
Новый процесс (дочерний) получает другой идентификатор процесса (PID) и имеет PID старого процесса (родителя) в качестве родительского PID (PPID). Поскольку два процесса теперь работают точно в одном и том же коде, они могут определить, какой именно, по коду возврата fork - дочерний элемент получает 0, родительский получает PID дочернего элемента. Конечно, это все, если предположить, что вызов fork работает - если нет, дочерний элемент не создается, а родительский код получает код ошибки.
Vfork
: Основное различие между vfork и fork заключается в том, что при создании нового процесса с помощью vfork () родительский процесс временно приостанавливается, и дочерний процесс может занимать адресное пространство родительского процесса. Это странное положение вещей продолжается до тех пор, пока дочерний процесс не завершится или не вызовет execve (), после чего родительский процесс продолжится.
Это означает, что дочерний процесс vfork () должен быть осторожен, чтобы избежать неожиданного изменения переменных родительского процесса. В частности, дочерний процесс не должен возвращаться из функции, содержащей вызов vfork (), и он не должен вызывать exit () (если ему нужно выйти, он должен использовать _exit (); на самом деле, это также верно для дочернего процесса нормальной вилки ()).
Exec :
Вызов exec - это способ в основном заменить весь текущий процесс новой программой. Он загружает программу в текущее пространство процесса и запускает ее из точки входа. exec () заменяет текущий процесс исполняемым файлом, указанным функцией. Элемент управления никогда не возвращается к исходной программе, если не существует ошибки exec ().
Clone :
Клон, как форк, создает новый процесс. В отличие от fork эти вызовы позволяют дочернему процессу совместно использовать часть своего контекста выполнения с вызывающим процессом, например пространство памяти, таблицу дескрипторов файлов и таблицу обработчиков сигналов.
Когда дочерний процесс создается с помощью clone, он выполняет функцию приложения fn (arg). (Это отличается от fork, где выполнение продолжается в дочернем элементе с точки исходного вызова fork.) Аргумент fn является указателем на функцию, которая вызывается дочерним процессом в начале его выполнения. Аргумент arg передается в функцию fn.
Когда возвращается функция функции fn (arg), дочерний процесс завершается. Целое число, возвращаемое fn, является кодом выхода для дочернего процесса. Дочерний процесс также может явно завершиться с помощью вызова exit (2) или после получения фатального сигнала.
Информация полученная форма:
- Различия между форком и exec
- http://www.allinterview.com/showanswers/59616.html
- http://www.unixguide.net/unix/programming/1.1.2.shtml
- http://linux.about.com/library/cmd/blcmdl2_clone.htm
Спасибо, что нашли время, чтобы прочитать это! :)
fork()
, как в Linux и, вероятно, во всех BSD), занимает адресное пространство своего родителя. Все, что он делает, кроме вызоваexecve()
или_exit()
, имеет большой потенциал, чтобы испортить родителя. В частности, обработчикиexit()
вызововatexit()
и другие «финализаторы», например: сбрасывает потоки stdio. Возвращение отvfork()
ребенка потенциально (то же самое предостережение, что и раньше) испортит стек родителя.fork
системный вызов?Ответы:
vfork()
это устаревшая оптимизация До хорошего управления памятьюfork()
делали полную копию памяти родителя, поэтому это было довольно дорого. поскольку во многих случаях заfork()
ним следовал aexec()
, который отбрасывает текущую карту памяти и создает новую, это было ненужным расходом. В наше времяfork()
не копирует память; он просто устанавливается как «копировать при записи», поэтомуfork()
+exec()
так же эффективен, как иvfork()
+exec()
.clone()
это системный вызов используетсяfork()
. с некоторыми параметрами он создает новый процесс, с другими он создает поток. разница между ними заключается в том, какие структуры данных (пространство памяти, состояние процессора, стек, PID, открытые файлы и т. д.) используются совместно или нет.источник
vfork
избавляет от необходимости временно выделять гораздо больше памяти только для того, чтобы ее можно было выполнятьexec
, и это все же более эффективно, чемfork
, даже если и не в такой степени. Таким образом, можно избежать необходимости перегружать память, просто чтобы огромная программа могла порождать дочерний процесс. Таким образом, не только повышение производительности, но может сделать его вообще возможным.exec
.execve()
заменяет текущий исполняемый образ другим, загруженным из исполняемого файла.fork()
создает дочерний процесс.vfork()
является исторически оптимизированной версиейfork()
, предназначенной для использования приexecve()
непосредственном вызовеfork()
. Оказалось, что он хорошо работает в не-MMU системах (гдеfork()
не может работать эффективно) и при использованииfork()
процессов с огромным объемом памяти для запуска небольшой программы (например, JavaRuntime.exec()
). POSIX стандартизировал,posix_spawn()
чтобы заменить эти последние два более современных использованияvfork()
.posix_spawn()
делает эквивалент afork()/execve()
, а также позволяет некоторую жонглирование между ними. Он должен заменитьfork()/execve()
, в основном для не-MMU платформ.pthread_create()
создает новую темуclone()
это специфичный для Linux вызов, который можно использовать для реализации чего угодно, отfork()
доpthread_create()
. Это дает много контроля. Вдохновленный наrfork()
.rfork()
это конкретный вызов Plan-9. Предполагается, что это будет общий вызов, обеспечивающий несколько степеней разделения между полными процессами и потоками.источник
fork()
- создает новый дочерний процесс, который является полной копией родительского процесса. Дочерний и родительский процессы используют разные виртуальные адресные пространства, которые изначально заполнены одними и теми же страницами памяти. Затем, когда оба процесса выполняются, виртуальные адресные пространства начинают все больше и больше различаться, поскольку операционная система выполняет ленивое копирование страниц памяти, которые записываются любым из этих двух процессов, и назначает независимые копии измененных страниц память для каждого процесса. Этот метод называется копирование при записи (COW).vfork()
- создает новый дочерний процесс, который является «быстрой» копией родительского процесса. В отличие от системного вызоваfork()
, дочерний и родительский процессы совместно используют одно и то же виртуальное адресное пространство. НОТА! Используя одно и то же виртуальное адресное пространство, и родитель, и потомок используют один и тот же стек, указатель стека и указатель инструкций, как в случае классическогоfork()
! Чтобы предотвратить нежелательное вмешательство между родительским и дочерним процессами, которые используют один и тот же стек, выполнение родительского процесса приостанавливается до тех пор, пока дочерний процесс не вызоветexec()
(создаст новое виртуальное адресное пространство и перейдет в другой стек) или_exit()
(завершение выполнения процесса). ).vfork()
является оптимизациейfork()
для модели "fork-and-exec". Это может быть выполнено в 4-5 раз быстрее, чемfork()
, потому что в отличие отfork()
(даже с учетом COW), реализацияvfork()
системного вызова не включает создание нового адресного пространства (выделение и настройка новых каталогов страниц).clone()
- создает новый дочерний процесс. Различные параметры этого системного вызова указывают, какие части родительского процесса должны быть скопированы в дочерний процесс, а какие будут разделены между ними. В результате этот системный вызов может использоваться для создания всех видов исполняемых объектов, начиная с потоков и заканчивая совершенно независимыми процессами. Фактически,clone()
системный вызов является базой, которая используется для реализацииpthread_create()
и всех семействfork()
системных вызовов.exec()
- сбрасывает всю память процесса, загружает и анализирует указанный исполняемый файл, устанавливает новый стек и передает управление точке входа загруженного исполняемого файла. Этот системный вызов никогда не возвращает управление вызывающей стороне и служит для загрузки новой программы в уже существующий процесс. Этот системный вызов вместе сfork()
системным вызовом образуют классическую модель управления процессами UNIX, которая называется «fork-and-exec».источник
vfork
настолько слабы, что было бы законно создатьvfork
синонимfork
(а POSIX.1-2008 полностью исключаетvfork
из спецификации). Если вам случится протестировать ваш код в системе, которая их синонимизирует (например, большинство BSD после 4.4, кроме NetBSD, ядра Linux до 2.2.0-pre6 и т. Д.), Он может работать, даже если вы нарушаетеvfork
контракт, а затем взорвитесь если вы запустите его в другом месте. Некоторые из тех, кто имитирует это с помощьюfork
(например, OpenBSD), все еще гарантируют, что родитель не возобновит работу до тех пор, пока ребенокexec
или дети не будут_exit
. Это смехотворно непереносимо.Все fork (), vfork () и clone () вызывают do_fork () для реальной работы, но с разными параметрами.
Для fork дочерний и родительский узел имеет независимую таблицу страниц VM, но, поскольку эффективность fork не будет на самом деле копировать какие-либо страницы, он просто установит все доступные для записи страницы только для чтения для дочернего процесса. Поэтому, когда дочерний процесс хочет что-то записать на этой странице, возникает исключение страницы, и ядро выделяет новую страницу, клонированную со старой страницы с разрешением на запись. Это называется «копировать при записи».
Для vfork виртуальная память принадлежит ребенку и отцу - именно поэтому отец и ребенок не могут бодрствовать одновременно, поскольку они будут влиять друг на друга. Таким образом, отец будет спать в конце do_fork () и просыпаться, когда дочерний вызов вызывает exit () или execve (), с тех пор ему будет принадлежать новая таблица страниц. Вот код (в do_fork ()), который спит отец.
Вот код (в mm_release (), вызываемый exit () и execve ()), который пробуждает отца.
Для sys_clone () это более гибко, так как вы можете ввести в него любые clone_flags. Поэтому pthread_create () вызывает этот системный вызов со многими clone_flags:
int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM);
Резюме: fork (), vfork () и clone () создадут дочерние процессы с различным монтированием ресурса совместного использования с родительским процессом. Мы также можем сказать, что vfork () и clone () могут создавать потоки (на самом деле они являются процессами, поскольку имеют независимую task_struct), поскольку они совместно используют таблицу страниц VM с родительским процессом.
источник
в fork () дочерний или родительский процесс будет выполняться на основе выбора процессора. Но в vfork (), конечно, дочерний процесс будет выполняться первым. после того, как дочерний процесс прекращен, родитель выполнит.
источник
vfork()
можно просто реализовать какfork()
.pid
) - операционная система может запланировать параллельный запуск нового процесса, если такая вещь имеет смысл (например, несколько процессоров). Если по какой-то причине вам нужно, чтобы эти процессы выполнялись в определенном последовательном порядке, вам нужна дополнительная синхронизация, которую не обеспечивает разветвление; честно говоря, вы, вероятно, даже не хотели бы развилки в первую очередь.vfork()
, ребенок бежит первым. Это на страницах руководства; казнь родителей приостанавливается до тех пор, пока ребенок не умрет или не умретexec
. И ниндзя посмотрите исходный код ядра. Нет способа реализоватьvfork()
это,fork()
потому что они передают разные аргументыdo_fork()
внутри ядра. Тем не менее, вы можете реализоватьvfork
с помощьюclone
системного вызова