почему fork и exec хранятся 2 отдельных вызова

Я понимаю разницу между fork, vfork, exec, execv, execp. Так что, пожалуйста, не разглагольствуйте об этом. Мой вопрос касается дизайна создания процесса unix. Почему дизайнеры подумали о создании двух отдельных вызовов ( fork и exec ) вместо того, чтобы оставить один плотный вызов ( spawn ). Был ли хороший дизайн API причиной того, что разработчики имели больше контроля над созданием процессов? Это из-за производительности, чтобы мы могли отложить выделение таблицы процессов и других структур ядра дочернему элементу до копирования при записи или копирования при доступе?


person loneranger    schedule 23.02.2011    source источник
comment
Как бы вы смоделировали fork, используя spawn?   -  person Šimon Tóth    schedule 23.02.2011
comment
не могу имитировать вилку с помощью spawn.. это комбинация fork и exec.   -  person loneranger    schedule 24.02.2011
comment
@Let_Me_Be зачем вообще нужен форк?   -  person Autodidact    schedule 15.12.2011


Ответы (5)


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

  • Настроить произвольный набор дескрипторов открытых файлов;
  • Изменить маску сигнала;
  • Установить текущий рабочий каталог;
  • Установить группу процессов и/или сеанс;
  • Установите пользователя, группу и дополнительные группы;
  • Установите жесткие и мягкие ограничения ресурсов;

...и многое другое. Если бы вы объединили эти вызовы в один вызов spawn(), у него должен был бы быть очень сложный интерфейс, чтобы иметь возможность кодировать все эти возможные изменения в дочерней среде — и если бы вы когда-нибудь добавили новую настройку, интерфейс нужно изменить. С другой стороны, отдельные шаги fork() и exec() позволяют вам использовать обычные системные вызовы (open(), close(), dup(), fcntl(), ...) для управления дочерней средой до exec(). Новая функциональность (например, capset()) легко поддерживается.

person caf    schedule 25.02.2011
comment
В Gould, когда я работал над UNIX реального времени, я разработал[*] системный вызов (на самом деле, их семейство), который позволял комбинировать fork и exec, т.е. который позволял вам избежать накладных расходов на первое ответвление, клонирование вашего текущий процесс, а затем подстановка другого образа процесса через exec - без kluge vfork. // Бот отличается от порождения POSIX, хотя я думаю, что он более общий. // Пришлось создать концепцию объекта процесса, который можно было бы загрузить из файла или клонировать из текущего процесса (или другого запущенного процесса). - person Krazy Glew; 09.08.2012
comment
Но также приходилось в основном брать каждый системный вызов и реализовывать версию, которую можно было бы применить к такому объекту процесса. Это означало предоставление дополнительного аргумента process_object_to_be_affected каждому системному вызову. С системными вызовами UNIX по умолчанию, являющимися вырожденными формами, с self в качестве process_object_to_be_affected. - person Krazy Glew; 09.08.2012
comment
Это выполнимо. Конечно, более общий, и я думаю, довольно полезный. (Например, порождение Posix было добавлено, потому что многие подражатели ОС просто не могли эффективно выполнять разветвление.) // Но это было много работы, хотя, возможно, только одна работа, которую нужно было сделать один раз. // Как бы то ни было, много работы => отменено, предложение отклонено после того, как я сделал первые несколько системных вызовов. // Примечание [*]: разработано = разработано, закодировано кое-что, но не все. Отменено. - person Krazy Glew; 09.08.2012
comment
И последнее наблюдение: с течением времени UNIX и Linux постепенно добавляли такую ​​функцию do syscall для удаленного процесса ко все большему количеству системных вызовов. Ptrace, в частности, может делать многие из этих вещей. Отладчики нужны. - person Krazy Glew; 09.08.2012

fork и exec делают совершенно разные вещи.

  • fork() - дублирует процесс
  • exec() - заменяет процесс

Есть много причин использовать одно без другого. Вы можете разветвить дочерние процессы, которые выполняют задачи от имени вашего управляющего родительского приложения, например, это довольно распространено в мире Unix. И вы можете, например. настройте предварительные условия для какого-то другого необычного приложения, а затем запустите его из своего приложения запуска, даже не используя fork.

person Erik    schedule 23.02.2011
comment
Или, что еще более распространено, используйте простой exec, перезапустите приложение (например, сетевые демоны делают это, если обнаруживают новую версию своего двоичного файла и простаивают). - person Šimon Tóth; 23.02.2011
comment
Не правда ли, системный вызов spawn можно было бы реализовать эффективнее, чем fork + exec? Мне кажется, что spawn не нужно копировать сегмент данных, как это делает fork. - person sasha.sochka; 10.02.2014
comment
@sasha.sochka Сегодня (и в 2014 году тоже) современные системы используют Copy-On-Write для forked процессов. - person val is still with Monica; 04.07.2018

Насколько я знаю, изначально была только функция fork(). Но соображения производительности требуют создания функции exec(), которая не воссоздает структуры ядра, которые будут немедленно перезаписаны. ‹-- Это неправильно.

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

person 9000    schedule 23.02.2011
comment
Если это правда, то как люди запускали программы без exec? - person Philipp; 23.02.2011

Из черновика книги xv6 простая обучающая операционная система в стиле Unix. система, используемая в курсе MIT 6.828:

Теперь должно быть ясно, почему это хорошая идея, чтобы fork и exec были отдельными вызовами. Потому что, если они разделены, оболочка может разветвить дочерний элемент, использовать open, close, dup в дочернем элементе для изменения стандартных дескрипторов входных и выходных файлов, а затем выполнить exec. Никаких изменений в исполняемой программе (cat в нашем примере) не требуется. Если бы fork и exec были объединены в один системный вызов, то для перенаправления стандартного ввода и вывода оболочке потребовалась бы какая-то другая (вероятно, более сложная) схема, или самой программе пришлось бы понимать, как перенаправлять ввод-вывод.

В основном, как говорит caf ниже, но дает хорошую ссылку. Реализация простой оболочки, вероятно, прояснила бы причины.

person George Co    schedule 17.03.2019

fork() можно использовать только для создания дочернего процесса. Можно выполнить только репликацию родителя. В то время как exec() можно использовать для запуска любого нового процесса в системе. Я не вижу никакой корреляции выше двух.

person Pradeep    schedule 23.02.2011
comment
Я думаю, что вопрос возникает из-за того, что в Windows нет fork или exec, а есть только их комбинация (на языке Unix за fork сразу следует exec). - person Philipp; 23.02.2011