Форк-exec
Эта статья включает список общих ссылок , но в ней отсутствуют достаточные соответствующие встроенные цитаты . ( Март 2022 г. ) |
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()
.
выполняется системный вызов fork Когда в WSL , lxss.sys выполняет часть начальной работы по подготовке к копированию процесса. Затем он вызывает внутренние API NT для создания процесса с правильной семантикой и создания потока в процессе с идентичным контекстом регистра. Наконец, он выполняет дополнительную работу для завершения копирования процесса и возобновляет новый процесс, чтобы он мог начать выполнение.
— Джек Хэммонс из Microsoft [1]
Ссылки
[ редактировать ]- «Дескрипторы файлов в fork(2)/exec(2)» , Операционные системы (курс 304-427B), Франко Каллари, факультет электротехники, Университет Макгилла
- «fork and exec» , Тим Лав, Кембриджского университета инженерный факультет
- Продвинутое программирование в среде UNIX , В. Ричард Стивенс , Аддисон-Уэсли ISBN 0-201-56317-7
- Unix Power Tools , Джерри Пик, Тим О'Рейли , Майк Лукидес, О'Рейли , ISBN 1-56592-260-3