Подтвердить что ты не робот

Что происходит, когда я вызываю fork() в Unix?

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

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

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

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

4b9b3361

Ответ 1

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

В действительности он использует систему "копировать на запись". В первый раз либо процесс изменяет свою память после fork(), отдельная копия делается из измененной страницы (обычно 4kB).

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

Ответ 2

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

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

Разделяется множество других вещей. Подробнее см. здесь.

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

Ответ 3

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

ИЗМЕНИТЬ: опечатки НТН

Ответ 4

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

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

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