Что происходит, когда я вызываю fork () в Unix? - PullRequest
18 голосов
/ 17 сентября 2011

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

Являются ли они полностью отдельными процессами, связанными только идентификатором / родительским идентификатором? Или они разделяют память? Например, раздел «код» каждого процесса - это , дублированный , чтобы у каждого процесса была своя собственная идентичная копия, или это каким-то образом «общий доступ», так что существует только один? »

Надеюсь, это имеет смысл.

Во имя полного раскрытия это «домашнее задание»; хотя это и не прямой вопрос из книги, я чувствую, что в основном это академический вопрос, и на практике мне, вероятно, не нужно это знать.

Ответы [ 4 ]

21 голосов
/ 17 сентября 2011

Как представляется процессу, вся память дублируется.

На самом деле используется система «копирование при записи».В первый раз, когда любой процесс меняет свою память после fork (), создается отдельная копия измененной страницы (обычно 4 КБ).

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

17 голосов
/ 17 сентября 2011

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

Файловые дескрипторы дублируются, так что разветвленный процесс может в принципе захватить соединение с базой данных от имени родителя (или они могут даже совместно взаимодействовать с базой данных, если программист немного искажен). Чаще всего это используется для настройки каналов между процессами, чтобы вы могли написать find -name '*.c' | xargs grep fork.

Куча других вещей доступна. Подробнее см. здесь .

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

5 голосов
/ 17 сентября 2011
  1. Это отдельные процессы, т. Е. У Дочернего и Родителя будут отдельные PID
  2. Дочерний объект будет наследовать все открытые дескрипторы от Родителя
  3. Внутренне страницы, т.е. стекОбласти / heap, которые могут быть изменены в отличие от области .text, будут совместно использоваться родителем и потомком, пока один из них не попытается изменить содержимое.В таких случаях создается новая страница, и данные, относящиеся к изменяемой странице, копируются на эту вновь выделенную страницу и сопоставляются с регионом, соответствующим тому, кто вызвал изменение, - это может быть родитель или потомок.Это называется COW (упомянуто другими участниками в этом форуме выше в их ответах).
  4. Ребенок может завершить выполнение и до тех пор, пока родительский вызов не будет вызван с помощью вызовов wait () или waitpid (), будет в состоянии ZOMBIE,Это поможет очистить запись дочернего процесса из таблицы процессов и позволит повторно использовать дочерний pid.Обычно, когда умирает дочерний элемент, сигнал SIGCHLD отправляется родителю, что в идеальном случае приводит к вызову обработчика, после которого в этом обработчике выполняется вызов wait ().
  5. В случае, если родительский объект завершается безПри очистке уже запущенного дочернего элемента или дочернего элемента-зомби (с помощью вызовов wait () waitpid) процесс init () (PID 1) становится родительским для этих теперь уже потерянных дочерних элементов.Этот процесс init () регулярно выполняет вызовы wait () или waitpid ().

РЕДАКТИРОВАТЬ: опечатки HTH

2 голосов
/ 17 сентября 2011

Да, это отдельные процессы, но с некоторыми особыми "свойствами".Одним из них является отношение «ребенок-родитель».

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

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

...