Fork (системный вызов)

редактировать
В вычислениях - операция, посредством которой процесс создает свою копию

В вычислениях., особенно в контексте операционной системы Unix и ее рабочих аналогов, fork - это операция, посредством которой процесс создает копия самого себя. Это интерфейс, который требуется для соответствия стандартам POSIX и Single UNIX Specification. Обычно он реализуется как стандартная библиотека C (libC) оболочка для fork, clone или других системных вызовов ядра ядра.. Fork - это основной метод создания процессов в Unix-подобных операционных системах.

Содержание

  • 1 Обзор
  • 2 История
  • 3 Связь
  • 4 Варианты
    • 4.1 Vfork
    • 4.2 Rfork
    • 4.3 Clone
  • 5 Форкинг в других операционных системах
  • 6 Использование приложений
  • 7 См. Также
  • 8 Ссылки

Обзор

В многозадачных операционных системах процессам (запущенным программам) нужен способ создания новых процессов, например для запуска других программ. Fork и его варианты обычно являются единственным способом сделать это в Unix-подобных системах. Чтобы процесс начал выполнение другой программы, он сначала создает копию самого себя. Затем копия, называемая «дочерний процесс », вызывает системный вызов exec, чтобы перекрыть себя другой программой: она прекращает выполнение своей предыдущей программы в пользу другой.

Операция fork создает отдельное адресное пространство для дочернего элемента. Дочерний процесс имеет точную копию всех сегментов памяти родительского процесса. В современных вариантах UNIX, которые следуют модели виртуальной памяти из SunOS-4.0, реализована семантика копирования при записи, и физическая память не требует фактического копирования. Вместо этого страницы виртуальной памяти в обоих процессах могут ссылаться на одни и те же страницы физической памяти, пока одна из них не запишет на такую ​​страницу: затем она будет скопирована. Эта оптимизация важна в общем случае, когда fork используется вместе с exec для выполнения новой программы: обычно дочерний процесс выполняет лишь небольшой набор действий, прежде чем он прекращает выполнение своей программы в пользу программы, которую нужно запустить, и ему требуется очень мало, если таковые имеются, из родительских структур данных .

. Когда процесс вызывает fork, он считается родительским процессом, а вновь созданный процесс является его дочерним процессом. После вилки оба процесса не только запускают одну и ту же программу, но и возобновляют выполнение, как если бы оба вызвали системный вызов. Затем они могут проверить возвращаемое значение вызова, чтобы определить свой статус, дочерний или родительский, и действовать соответственно.

История

Одна из самых ранних ссылок на концепцию вилки появилась в книге Мелвина Конвея «Проектирование многопроцессорной системы», опубликованной в 1962 году. Статья Конвея мотивировала реализацию L. Питер Дойч из форка системы разделения времени GENIE, где концепция была заимствована Кеном Томпсоном для ее самого раннего появления в Research Unix. Позже вилка стала стандартным интерфейсом в POSIX.

Communication

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

Варианты

Vfork

Vfork - это вариант fork с тем же соглашением о вызовах и почти такой же семантикой, но только для использования в ограниченных ситуациях. Он возник в версии Unix 3BSD, первой Unix, поддерживающей виртуальную память. Он был стандартизирован POSIX, который позволял vfork иметь точно такое же поведение, что и fork, но был отмечен как устаревший в редакции 2004 года и был заменен на posix_spawn () (который обычно реализуется через vfork) в последующих редакциях..

Когда выполняется системный вызов vfork, родительский процесс будет приостановлен до тех пор, пока дочерний процесс не завершит выполнение или не будет заменен новым исполняемым образом через один из семейства "exec " системных вызовов. Дочерний элемент заимствует настройку MMU у родительского, и страницы памяти совместно используются родительским и дочерним процессами без копирования и, в частности, без семантики copy-on-write ; следовательно, если дочерний процесс вносит изменения в любую из общих страниц, новая страница не будет создана, и измененные страницы также будут видны родительскому процессу. Поскольку при этом абсолютно не задействуется копирование страниц (потребление дополнительной памяти), этот метод является оптимизацией по сравнению с обычным fork в средах с полным копированием при использовании с exec. В POSIX использование vfork для любых целей, кроме как прелюдия к немедленному вызову функции из семейства exec (и некоторых других операций), приводит к неопределенному поведению. Как и в случае с vfork, дочерний элемент заимствует структуры данных, а не копирует их, vfork по-прежнему работает быстрее, чем вилка, использующая семантику копирования при записи.

Система V не поддерживала этот вызов функции до того, как была представлена ​​система VR4, потому что совместное использование памяти, которое она вызывает, подвержено ошибкам:

Vfork не копирует таблицы страниц, поэтому он работает быстрее, чем вилка System V. реализация. Но дочерний процесс выполняется в том же физическом адресном пространстве, что и родительский процесс (до выполнения или выхода) и, таким образом, может перезаписать данные и стек родительского объекта. Опасная ситуация может возникнуть, если программист неправильно использует vfork, поэтому ответственность за вызов vfork лежит на программисте. Разница между подходом System V и подходом BSD носит философский характер: должно ли ядро ​​скрывать особенности своей реализации от пользователей или оно должно предоставлять опытным пользователям возможность использовать преимущества реализации для более эффективного выполнения логической функции?

— Морис Дж. Бах

Аналогичным образом, справочная страница Linux для vfork настоятельно не рекомендует его использовать:

К сожалению, Linux возродил этот призрак из прошлого. На странице руководства BSD говорится: «Этот системный вызов будет удален, когда будут реализованы надлежащие механизмы совместного использования системы. Пользователи не должны зависеть от семантики разделения памяти vfork (), поскольку в этом случае он будет синонимом fork (2).. "

Другие проблемы с vfork включают взаимоблокировки, которые могут возникнуть в многопоточных программах из-за взаимодействия с динамической компоновкой. В качестве замены интерфейса vfork, POSIX представил семейство функций posix_spawn, которые объединяют действия fork и exec. Эти функции могут быть реализованы как библиотечные подпрограммы в терминах вилки, как это сделано в Linux, или в терминах vfork для повышения производительности, как это сделано в Solaris, но в спецификации POSIX отмечается, что они были «разработаны as операции ядра ", особенно для операционных систем, работающих на ограниченном оборудовании, и систем реального времени.

. В то время как реализация 4.4BSD избавилась от реализации vfork, в результате чего vfork ведет себя так же, как fork, позже он был восстановлен в операционной системе NetBSD для повышения производительности.

Некоторые встроенные операционные системы, такие как uClinux, пропускают fork и реализуют только vfork, потому что им нужно для работы на устройствах, где копирование при записи невозможно реализовать из-за отсутствия MMU.

Rfork

Операционная система Plan 9, созданная разработчиками Unix включает вилку, но также вариант под названием «rfork», который позволяет детально разделить ресурсы между родительскими и дочерними процессами, включая t адресное пространство (за исключением сегмента стека , который уникален для каждого процесса), переменные среды и пространство имен файловой системы; это делает его единым интерфейсом для создания обоих процессов и потоков внутри них. И FreeBSD, и IRIX переняли системный вызов rfork из Plan 9, последний переименовал его в «sproc».

Clone

clone- это системный вызов в Ядро Linux, которое создает дочерний процесс, который может совместно использовать части своего выполнения контекст с родительским. Подобно rfork FreeBSD и sproc от IRIX, клон Linux был вдохновлен rfork Plan 9 и может использоваться для реализации потоков (хотя прикладные программисты обычно используют интерфейс более высокого уровня, такой как pthreads, реализованный поверх клона). Функция «раздельных стеков» из Plan 9 и IRIX была опущена, потому что (согласно Линусу Торвальдсу ) она вызывает слишком много накладных расходов.

Форкинг в других операционных системах

В первоначальной разработке операционной системы VMS (1977 г.) операция копирования с последующим изменением содержимого нескольких конкретных адресов для нового процесса, как при разветвлении, считалась рискованной. Ошибки в текущем состоянии процесса могут быть скопированы в дочерний процесс. Здесь используется метафора порождения процесса: каждый компонент структуры памяти нового процесса создается заново с нуля. Метафора порождения была позже принята в операционных системах Microsoft (1993).

Компонент совместимости с POSIX в VM / CMS (OpenExtensions) предоставляет очень ограниченную реализацию fork, в которой родительский элемент приостанавливается на время выполнения дочернего, а дочерний и родительский общие ресурсы то же адресное пространство. По сути, это вилка, обозначенная как вилка. (Обратите внимание, что это относится только к гостевой операционной системе CMS; другие гостевые операционные системы виртуальных машин, такие как Linux, предоставляют стандартные функции вилки.)

Использование приложений

Следующий вариант Программа Hello World демонстрирует механизм системного вызова fork на языке программирования C. Программа разделяется на два процесса, каждый из которых определяет, какие функции они выполняют, на основе возвращаемого значения системного вызова fork. Код шаблона, такой как включения заголовка, был опущен.

int main (недействительно) {pid_t pid = fork (); если (pid == -1) {perror ("ошибка вилки"); выход (EXIT_FAILURE); } else if (pid == 0) {printf ("Привет от дочернего процесса! \ n"); _exit (EXIT_SUCCESS); } else {int status; (void) waitpid (pid, status, 0); } return EXIT_SUCCESS; }

Ниже приводится анализ этой программы.

pid_t pid = fork ();

Первый оператор в main вызывает системный вызов fork для разделения выполнения на два процесса. Возвращаемое значение fork записывается в переменную типа pid_t, которая является типом POSIX для идентификаторов процессов (PID).

if (pid == -1) {perror ("ошибка вилки"); выход (EXIT_FAILURE); }

Минус один указывает на ошибку в fork: новый процесс не был создан, поэтому выводится сообщение об ошибке.

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

else if (pid == 0) {printf ("Привет от дочернего процесса! \ N"); _exit (EXIT_SUCCESS); }

В дочернем процессе возвращаемое значение отображается как ноль (что является недопустимым идентификатором процесса). Дочерний процесс печатает желаемое приветственное сообщение и завершает работу. (По техническим причинам здесь должна использоваться функция POSIX _exit вместо стандартной функции выхода C.)

else {int status; (void) waitpid (pid, status, 0); }

Другой процесс, родительский, получает от fork идентификатор процесса дочернего процесса, который всегда является положительным числом. Родительский процесс передает этот идентификатор системному вызову waitpid, чтобы приостановить выполнение, пока дочерний процесс не выйдет. Когда это произошло, родительский элемент возобновляет выполнение и завершает работу с помощью оператора return.

См. Также

Ссылки

Последняя правка сделана 2021-05-20 11:36:44
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте