Вилка (системный вызов) - Fork (system call)

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

Обзор

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

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

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

История

Одна из самых ранних ссылок на концепцию вилки появилась в Дизайн многопроцессорной системы к Мелвин Конвей, опубликовано в 1962 году.[1] Статья Конвея мотивировала реализацию Л. Питер Дойч вилки в Система разделения времени GENIE, где концепция была заимствована Кен Томпсон за его самое раннее появление[2] в Исследование Unix.[3][4] Позже вилка стала стандартным интерфейсом в POSIX.[5]

Коммуникация

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

Варианты

Vfork

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

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

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

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

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

Точно так же справочная страница Linux для vfork настоятельно не рекомендует его использовать:[7][неудачная проверка ][обсуждать]

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

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

Хотя реализация 4.4BSD избавилась от реализации vfork, что привело к тому, что vfork ведет себя так же, как fork, позже он был восстановлен в NetBSD операционная система по соображениям производительности.[8]

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

Рфорк

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

Клонировать

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

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

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

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

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

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

int главный(пустота){    pid_t пид = вилка();    если (пид == -1) {        перрор("вилка не удалась");        выход(EXIT_FAILURE);    }    еще если (пид == 0) {        printf(«Привет от дочернего процесса! п");        _выход(EXIT_SUCCESS);    }    еще {        int положение дел;        (пустота)waitpid(пид, &положение дел, 0);    }    возвращаться EXIT_SUCCESS;}

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

   pid_t пид = вилка();

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

    если (пид == -1) {        перрор("вилка не удалась");        выход(EXIT_FAILURE);    }

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

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

   еще если (пид == 0) {      printf(«Привет от дочернего процесса! п");      _выход(EXIT_SUCCESS);   }

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

   еще {      int положение дел;      (пустота)waitpid(пид, &положение дел, 0);   }

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

Смотрите также

Рекомендации

  1. ^ Найман, Линус (25 августа 2016 г.). «Заметки по истории развилки и соединения». IEEE Annals of the History of Computing. 38 (3): 84–87. Дои:10.1109 / MAHC.2016.34.
  2. ^ "s3.s от Research UNIX". GitHub. 1970.
  3. ^ Кен Томпсон и Деннис Ричи (3 ноября 1971 г.). "СИСТЕМНАЯ ВИЛКА (II)" (PDF). Руководство программиста UNIX. Bell Laboratories.
  4. ^ Ричи, Деннис М.; Томпсон, Кен (июль 1978 г.). «Система разделения времени UNIX» (PDF). Bell System Tech. J. AT&T. 57 (6): 1905–1929. Дои:10.1002 / j.1538-7305.1978.tb02136.x. Получено 22 апреля 2014.
  5. ^ а б вилка - Справочник по системным интерфейсам, Единая спецификация UNIX, Выпуск 7 из Открытая группа
  6. ^ трубка - Справочник по системным интерфейсам, Единая спецификация UNIX, Выпуск 7 из Открытая группа
  7. ^ а б вилки (2) – Linux Программиста Руководство - Системные вызовы
  8. ^ а б «Документация NetBSD: зачем реализовывать традиционный vfork ()». Проект NetBSD. Получено 16 октября 2013.
  9. ^ "vfork (2)". Руководство программиста UNIX, версия Virtual VAX-11. Калифорнийский университет в Беркли. Декабрь 1979 г.
  10. ^ а б c vfork - Справочник по системным интерфейсам, Единая спецификация UNIX, Выпуск 6 из Открытая группа
  11. ^ Бах, Морис Дж. (1986). Дизайн операционной системы UNIX. Прентис-Холл. С. 291–292. Bibcode:1986duos.book ..... B.
  12. ^ а б c Нахимовский, Грег (2006). «Минимизация использования памяти для создания подпроцессов приложений». Технологическая сеть Oracle. Корпорация Oracle.
  13. ^ Реализация OpenSolaris posix_spawn (): https://sourceforge.net/p/schillix-on/schillix-on/ci/default/tree/usr/src/lib/libc/port/threads/spawn.c
  14. ^ posix_spawn - Справочник по системным интерфейсам, Единая спецификация UNIX, Выпуск 7 из Открытая группа
  15. ^ вилка (2) – План 9 Руководство программиста, том 1
  16. ^ вступление (2) – План 9 Руководство программиста, том 1
  17. ^ вилы (2) – FreeBSD Системные вызовы Руководство
  18. ^ а б Торвальдс, Линус (1999). «Край Linux». Открытые источники: голоса революции открытого исходного кода. О'Рейли. ISBN  978-1-56592-582-3.
  19. ^ "z / VM> z / VM 6.2.0> Программирование приложений> z / VM V6R2 OpenExtensions Документ соответствия POSIX> Документ соответствия POSIX.1> Раздел 3. Примитивы процессов> 3.1 Создание и выполнение процессов> 3.1.1 Создание процесса". IBM. Получено 21 апреля, 2015.