stringtranslate.com

Форк – исполнительный

Fork-exec — это широко используемый метод в Unix , при котором исполняемый процесс порождает новую программу.

Описание

fork()— это имя системного вызова , который родительский процесс использует для «разделения» себя («разветвления») на два идентичных процесса. После вызова fork()созданный дочерний процесс является точной копией родительского, за исключением возвращаемого значения вызова fork(). Сюда входят открытые файлы, состояние регистров и все выделения памяти, включая исполняемый код программы. В некоторых случаях оба продолжают запускать один и тот же двоичный файл, но часто один (обычно дочерний) переключается на запуск другого двоичного исполняемого файла с помощью системного exec()вызова.

Когда процесс разветвляется, полная копия исполняемой программы превращается в новый процесс. Этот новый процесс является дочерним по отношению к родительскому процессу и имеет новый идентификатор процесса (PID). Функция fork()возвращает PID дочернего процесса родительскому процессу. Функция fork()возвращает 0 дочернему процессу. Это позволяет двум идентичным процессам отличаться друг от друга.

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

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

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

 void cleanup ( int signal ) { while ( waitpid (( pid_t ) ( -1 ), 0 , WNOHANG ) > 0 ) {} }            

Когда дочерний процесс вызывает exec(), все данные исходной программы теряются и заменяются работающей копией новой программы. Это известно как наложение . Хотя все данные заменяются, дескрипторы файлов , которые были открыты в родительском файле, закрываются только в том случае, если программа явно пометила их как close-on-exec . Это позволяет использовать обычную практику, когда родитель создает канал перед вызовом fork()и использует его для связи с исполняемой программой.

Microsoft Windows не поддерживает модель fork-exec, поскольку в ней нет системного вызова, аналогичного fork(). Семейство spawn()функций, объявленное в файлеprocess.h, может заменить его в тех случаях, когда за вызовом fork()следует непосредственно exec().

Когда в WSL выполняется системный вызов fork , lxss.sys выполняет часть начальной работы по подготовке к копированию процесса. Затем он вызывает внутренние API NT для создания процесса с правильной семантикой и создания потока в процессе с идентичным контекстом регистра. Наконец, он выполняет дополнительную работу для завершения копирования процесса и возобновляет новый процесс, чтобы он мог начать выполнение.

—  Джек Хэммонс из Microsoft [1]

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

  1. ^ «Системные вызовы WSL».