Как работают fork и exec?

17

У меня нет большого опыта, я просто пытаюсь участвовать в процессах, как они интерпретируют оборудование на уровне пользователя.

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

  1. Если дочерний процесс содержит все атрибуты родительского процесса (который является исходным процессом), то зачем нужен этот дочерний процесс? Исходный процесс также мог быть загружен в память.
  2. Относится ли это forkи execконцепция ко всем исполняемым программам в UNIX? Как и для сценария оболочки также или только для команд? Это также относится к встроенным командам оболочки?
  3. Когда используется концепция копирования при записи, если я выполню команду / скрипт?

Извините, что задаю много вопросов одновременно, но все эти вопросы приходят мне на ум сразу, когда я думаю о выполнении любой команды.

Приб
источник
Я не буду говорить, что это дубликат, но я думаю, что на некоторые из ваших вопросов ответ здесь: unix.stackexchange.com/questions/136637/… и в другом ответе, связанном в верхней части этого.
Златовласка

Ответы:

22

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

Не совсем. fork()клонирует текущий процесс, создавая идентичного потомка. exec()загружает новую программу в текущий процесс, заменяя существующую.

Мой вопрос:

Если дочерний процесс содержит все атрибуты родительского процесса (который является исходным процессом), то зачем нужен этот дочерний процесс? Исходный процесс также мог быть загружен в память.

Необходимость в том, что родительский процесс еще не хочет завершаться; он хочет, чтобы новый процесс завершился и сделал что-то одновременно с продолжением выполнения.

Применяется ли эта концепция fork и exec ко всем исполняемым программам в UNIX? Также как для сценария оболочки или только для команд? Это также относится к встроенным командам оболочки?

Для внешних команд оболочка делает fork()так, чтобы команда выполнялась в новом процессе. Встроенные команды запускаются непосредственно оболочкой. Еще одна известная команда exec, которая сообщает оболочке exec()внешней программе без предварительного fork()вызова. Это означает, что сама оболочка заменена новой программой, и, следовательно, больше не существует этой программы для возврата к ней, когда она завершает работу. Если вы скажете, exec trueто /bin/trueзамените вашу оболочку и немедленно выйдете, и в вашем терминале больше ничего не будет работать, поэтому он закроется.

когда используется концепция копирования при записи, если я выполню команду / скрипт?

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

psusi
источник
4
«Почти для каждой команды оболочка выполняет fork (), чтобы команда выполнялась в новом процессе. Если эта команда является встроенной, тогда дочернему элементу не требуется выполнять exec () отдельную программу». Хороший ответ, но эта часть должна быть отредактирована. Оболочка не разветвляется при запуске buildins. Он запускает их непосредственно в активном процессе оболочки. Это единственный способ, которым встроенные функции любят cdили readмогут работать. Отсутствие разветвления также делает встроенные функции намного быстрее, чем внешние команды.
Джон Кугельман поддерживает Монику
6
  1. Для некоторых программ дочерний процесс выполняет одно действие (чтение из последовательного порта, запись в терминал), а родительский процесс продолжает делать что-то другое (чтение из терминала, запись в последовательный порт). Другим классическим примером является то, что дочерний процесс делает контрольную точку любого продолжительного вычисления. В основном, дочерний процесс выполняет некоторую настройку, такую ​​как изменение каталога, сброс обработчиков сигналов или сброс файловых дескрипторов, а затем вызывает execve()наложение себя другим кодом.
  2. fork()и exec()применимы ко всем исполняемым файлам - фактически, наряду с argc и argv, а pipe, fork и exec - это то, что отличает Unix от других операционных систем. Существует несколько специализаций или обобщений fork(), таких как BSD vfork(), Plan 9 rfork()и Linux clone(), но принцип остается тем же.
  3. «копирование при записи» на самом деле не показывается пользователю, это скорее техника для оптимизации создания дочернего процесса и во время его выполнения. Стек вызовов и куча (память, выделенная malloc()или даже статические или глобальные переменные области видимости) могут быть «копировать при записи». Когда дочерний процесс создается сfork()При вызове ядро ​​настроит дочерний процесс так, чтобы он имел те же самые страницы памяти, что и куча, и стек, как родительский процесс. Если оборудование (модуль управления памятью) обнаруживает запись в кучу или стек, ядро ​​получит новую физическую страницу памяти, скопирует страницу родителя на новую страницу и отобразит эту новую страницу в стеке или куче дочернего процесса. Это представляет собой оптимизацию, поскольку ядро ​​тратит меньше времени на настройку отображений страниц, чем полностью копирует стек и кучу для дочернего процесса.
Брюс Эдигер
источник
Спасибо Брюс за твой ответ. Но так много вещей, которые вы сказали здесь, которые происходят у меня над головой. Я не очень разбираюсь в этих вещах ... Я постараюсь, чтобы эти функции работали, как вы упомянули. Огромное спасибо..!!
Приб
4
Если дочерний процесс содержит все атрибуты родительского процесса (который является исходным процессом), то зачем нужен этот дочерний процесс? Исходный процесс также мог быть загружен в память.

На этот вопрос очень наглядно дан ответ, взглянув на самые ранние реализации Unix, которые должны были работать при жестких ограничениях памяти и иметь только один выполняющийся процесс в памяти / адресном пространстве одновременно.

Многозадачность была достигнута путем помещения процесса на диск и замены другого процесса в.

Теперь forkсистемный вызов был почти таким же: он перенес процесс на диск, но вместо того, чтобы поменять другой процесс, он дал копии в памяти другой идентификатор процесса и вернулся к нему. И это было подходящим моментом для этого процесса, чтобы execв конце концов принять решение просто включить другой исполняемый файл.

fork+, execтаким образом, на самом деле не было заметных накладных расходов на нерест: вы все равно должны были выгружать процесс на диск, и в любом случае старый образ процесса находился в работоспособных местах памяти.

С ростом количества доступной памяти и модулей управления памятью и множественных процессов в памяти изначально незначительная стоимость разветвления стала несколько более неприятной для некоторых архитектур: таким образом, vforkона и родилась.

user99727
источник
2

Чтобы сделать это как можно более понятным, я буду использовать аналогию. Давайте испечь пирог!

Мы берем книгу рецептов, начинаем читать и садимся на клубничный пирог с ревенем (мой любимый) с корочкой ручной работы. Почти все, что нам нужно, находится на кухне, кроме яиц и фруктов, но поскольку мы живем на ферме, а фрукты в сезон, это не проблема. проблема в том, что духовка сломалась, и не хватает времени, чтобы все сделать. Разве не было бы хорошо иметь больше одного из меня?

fork () на помощь. Теперь меня двое. и мы оба идем на кухню, чтобы начать делать корку пирога. упс. Итак, мы смотрим на возврат от форка. Я получил большое число, он получил ноль, поэтому я иду на кухню, а он направляется в курятник и в сад. Проходя мимо духовки, я снова форкаю (), посмотрим на возвращаемое значение: облом я получил ноль. Он продолжает муку, а я смотрю на сломанную духовку. Я открываю дверь, Нет света, я закрываю дверь. Кто-нибудь знает, как починить духовку?

exec () на помощь. Дотягиваясь до вольтметра на ремне с инструментами, лампочка может быть диагностической, поэтому я проверяю мощность, действительно отключенный выключатель, легко исправить. когда я иду к панели выключателя, я вижу парня, который собирает ревень. Тьфу! Я предпочитаю шоколадный шелковый пирог.

hildred
источник