Зачем нам нужен системный вызов wait()?

Здравствуйте, я новичок в изучении системных вызовов. В настоящее время я изучаю системные вызовы fork() и wait(). Я знаю, что fork() создает новый дочерний процесс. Что меня смущает, так это вызов wait().
Вот что я понимаю до сих пор:
(1) Когда процесс умирает, он переходит в «состояние зомби», т.е. он не выпускает свой PID, а ждет, пока его родитель подтвердит, что дочерний процесс умер, а затем освобождается PID
(2) Итак, нам нужен способ выяснить, когда завершился дочерний процесс, чтобы мы не оставляли процессы в состоянии зомби

Меня смущают следующие вещи:
(1) При запуске программы на C, в которой я разветвляю новый дочерний процесс, если я не вызываю wait() явно, выполняется ли это внутренне, когда дочерний процесс завершается? Потому что вы все еще можете написать блок кода на C, где вы запускаете fork() без wait(), и кажется, что он работает нормально?
(2) Что делает wait()? Я знаю, что он возвращает PID дочернего процесса, который был завершен, но как это полезно/связано с выпуском PID завершенного процесса?

Прошу прощения за такие наивные вопросы, но мне было очень любопытно, и я не смог найти хороших ресурсов в Интернете! Ваша помощь очень ценится!


person JANVI SHARMA    schedule 29.09.2020    source источник


Ответы (2)


wait не предотвращает состояния зомби. Зомби государства ваш друг.

POSIX более или менее позволяет вам делать две вещи с pids: сигнализировать им с помощью kill или пожинать их (и синхронизировать с ними) с помощью wait/waitpid/waittid.

Системные вызовы wait в первую очередь предназначены для ожидания завершения процесса или его остановки из-за сигнала (хотя их также можно использовать для ожидания других изменений состояния процесса, таких как остановка дочернего процесса или пробуждение дочернего процесса после остановки).

Во-вторых, они собирают статусы выхода/умирания, тем самым высвобождая (зомбированные) pid.

Пока вы не отпустите pid с wait/waitpid/waittid, вы можете продолжать бить pid просьбами о его смерти (kill(pid,SIGTERM);) или каким-либо другим сигналом (отличным от SIGKILL), и вы можете быть уверены, что pid представляет процесс, который вы разветвлен и что вы случайно не убиваете чужой процесс.

Но как только вы пожинаете зомбированный pid путем waitинга на нем, тогда pid больше не ваш, и его может взять другой процесс (что обычно происходит через некоторое время, так как pid в системе обычно увеличиваются, а затем циклически обтекаются).

Вот почему автоматическое ожидание было бы плохой идеей (в некоторых случаях это не так, и тогда вы можете добиться этого глобально с помощью signal(SIGCHLD,SIG_IGN);) и почему (кратковременные) состояния зомби — ваш друг. Они сохраняют ребенка pid в стабильном состоянии до тех пор, пока вы не будете готовы его отпустить.

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

person PSkocik    schedule 29.09.2020
comment
Спасибо за ваш ответ! это весьма полезно! тогда быстрый вопрос: если мы используем вызов wait9) для ожидания завершения дочернего процесса, мне было интересно, почему он ждет завершения только одного дочернего процесса, а не ждет завершения всех его дочерних процессов? в любом случае, я буду читать больше в нем! Спасибо за вашу помощь - person JANVI SHARMA; 30.09.2020
comment
Пожалуйста. Поскольку разработчики UNIX решили, что для ожидания всех процессов следует вызывать wait в цикле, пока не будет получено ECHILD. - person PSkocik; 30.09.2020

Когда вы вызываете fork(), создается новый процесс, и вы являетесь его родителем. Когда дочерний процесс завершает свое выполнение вызовом exit(), его дескриптор процесса все еще хранится в памяти ядра. Вы, как его родитель, несете ответственность за сбор его кода выхода, что делается с помощью вызова wait() syscall. wait() блокирует родительский процесс, пока один из его дочерних процессов не завершится.

Зомби-процесс — это имя процесса, код выхода которого никогда не собирался его родителем.

Что касается вашего первого вопроса - wait() не вызывается автоматически, поскольку в противном случае процессы-зомби не существовали бы. Это ваша ответственность как программиста. Пропуск вызова wait() все равно будет работать, как вы упомянули, но это считается плохой практикой.

Оба эта ссылка и ссылка эта ссылка хорошо объясняет.

person SpiderPig1297    schedule 29.09.2020