Меню Рубрики

Linux ожидание завершения процесса

🐧 Команда wait в Linux с примерами

Wait — это команда shell, которая ожидает завершения определенного процесса, а затем возвращает его состояние завершения.

Команда wait используется для ожидания определенного идентификатора процесса и идентификатора задания и возврата их статуса завершения.

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

Как работает команда wait

Команда wait, используемая для наблюдения за предыдущим процессом, зависит от состояния возврата предыдущего процесса и возвращает статус выхода.

Например, если мы хотим дождаться завершения определенного идентификатора процесса 13245, то мы должны использовать «ждать 13245», когда процесс 13245 завершает команду ожидания, возвращающую значения 13245 состояния выхода.

— wait PID (PID — идентификатор процесса команды, для которой утилита ожидает завершения).
— wait JID (JID — идентификатор задания, который идентифицирует фоновый процесс, ожидающий wait, применим только для вызовов wait в текущей среде выполнения оболочки).

Значение состояния выхода команды ожидания зависит от последнего указанного PID / JID.

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

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

Если команда wait обнаруживает какую-либо ошибку, она возвращает любое значение от 1 до 126 .

Если последний идентификатор процесса неизвестен, команда ожидания завершается со значением 127.

Примеры команд wait

Давайте проверим несколько скриптов, чтобы понять, как работает команда wait.

Пример: 1 — скрипт с командой wait

У нас есть два скрипта с именами «foo.sh» и «bar.sh».

Скрипт «Foo.sh» выводит числа от 1 до 5, а скрипт «bar.sh» вызывает foo.sh и запускает его в фоновом режиме, получает PID для foo.sh и ожидает его завершения, после его завершения начнинает цикл ‘bar.sh’ и завершается.

Пример 2 — Скрипт без команды wait

У нас есть два скрипта с именами «foo.sh» и «bar.sh».

Скрипт ‘foo.sh’ выводит числа от 1 до 5, а скрипт bar.sh вызывает foo.sh и запускает его в фоновом режиме, но не будет ждать завершения foo.sh и выполнения обоих скриптов.

Пример: 3 — Скрипт с командой wait и статусом возврата

Скрипт ‘bar.sh’ вызовет foo.sh и запустит его в фоновом режиме, получит PID файла foo.sh и дождется его завершения, после его завершения запустится цикл bar.sh и завершится.

Наконец, он возвращает код выхода скрипта foo.sh

Скрипт — foo.sh (статус выхода = 0)

Скрипт — foo.sh (статус выхода = NON ZERO)

Заключение

Wait и Sleep — это системные вызовы в операционной системе, основанные на времени.

Давайте посмотрим разницу между командами wait и sleep.

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

Нам нужно использовать notify, чтобы этот процесс знал, что надо начать выполнение снова после завершения другого процесса.

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

Источник

Linux ожидание завершения процесса

Процесс может синхронизировать продолжение своего выполнения с моментом завершения потомка, если воспользуется системной функцией wait. Синтаксис вызова функции:

где pid — значение кода идентификации (PID) прекратившего свое существование потомка, stat_addr — адрес переменной целого типа, в которую будет помещено возвращаемое функцией exit значение, в пространстве задачи.

Рисунок 7.15. Пример использования функции exit

Алгоритм функции wait приведен на Рисунке 7.16. Ядро ведет поиск потомков процесса, прекративших существование, и в случае их отсутствия возвращает ошибку. Если потомок, прекративший существование, обнаружен, ядро передает его код идентификации и значение, возвращаемое через параметр функции exit, процессу, вызвавшему функцию wait. Таким образом, через параметр функции exit (status) завершающийся процесс может передавать различные значения, в закодированном виде содержащие информацию о причине завершения процесса, однако на практике этот параметр используется по назначению довольно редко. Ядро передает в соответствующие поля, принадлежащие пространству родительского процесса, накопленные значения продолжительности исполнения процесса-потомка в режиме ядра и в режиме задачи и, наконец, освобождает в таблице процессов место, которое в ней занимал прежде прекративший существование процесс. Это место будет предоставлено новому процессу.

Если процесс, выполняющий функцию wait, имеет потомков, продолжающих существование, он приостанавливается до получения ожидаемого сигнала. Ядро не возобновляет по своей инициативе процесс, приостановившийся с помощью функции wait: такой процесс может возобновиться только в случае получения сигнала. На все сигналы, кроме сигнала «гибель потомка», процесс реагирует ранее рассмотренным образом. Реакция процесса на сигнал «гибель потомка» проявляется по-разному в зависимости от обстоятельств:

  • По умолчанию (то есть если специально не оговорены никакие другие действия) процесс выходит из состояния останова, в которое он вошел с помощью функции wait, и запускает алгоритм issig для опознания типа поступившего сигнала. Алгоритм issig (Рисунок 7.7) рассматривает особый случай поступления сигнала типа «гибель потомка» и возвращает «ложь». Поэтому ядро не выполняет longjump из функции sleep, а возвращает управление функции wait. Оно перезапускает функцию wait, находит потомков, прекративших существование (по крайней мере, одного), освобождает место в таблице процессов, занимаемое этими потомками, и выходит из функции wait, возвращая управление процессу, вызвавшему ее.
  • Если процессы принимает сигналы данного типа, ядро делает все необходимые установки для запуска пользовательской функции обработки сигнала, как и в случае поступления сигнала любого другого типа.
  • Если процесс игнорирует сигналы данного типа, ядро перезапускает функцию wait, освобождает в таблице процессов место, занимаемое потомками, прекратившими существование, и исследует оставшихся потомков.

Рисунок 7.16. Алгоритм функции wait

Например, если пользователь запускает программу, приведенную на Рисунке 7.17, с параметром и без параметра, он получит разные результаты. Сначала рассмотрим случай, когда пользователь запускает программу без параметра (единственный параметр — имя программы, то есть argc равно 1). Родительский процесс порождает 15 потомков, которые в конечном итоге завершают свое выполнение с кодом возврата i, номером процесса в порядке очередности создания. Ядро, исполняя функцию wait для родителя, находит потомка, прекратившего существование, и передает родителю его идентификатор и код возврата функции exit. При этом заранее не известно, какой из потомков будет обнаружен. Из текста программы, реализующей системную функцию exit, написанной на языке Си и включенной в библиотеку стандартных подпрограмм, видно, что программа запоминает код возврата функции exit в битах 8-15 поля ret_code и возвращает функции wait идентификатор процесса-потомка. Таким образом, в ret_code хранится значение, равное 256*i, где i — номер потомка, а в ret_val заносится значение идентификатора потомка.

Если пользователь запускает программу с параметром (то есть argc > 1), родительский процесс с помощью функции signal делает распоряжение игнорировать сигналы типа «гибель потомка». Предположим, что родительский процесс, выполняя функцию wait, приостановился еще до того, как его потомок произвел обращение к функции exit: когда процесс-потомок переходит к выполнению функции exit, он посылает своему родителю сигнал «гибель потомка»; родительский процесс возобновляется, поскольку он был приостановлен с приоритетом, допускающим прерывания. Когда так или иначе родительский процесс продолжит свое выполнение, он обнаружит, что сигнал сообщал о «гибели» потомка; однако, поскольку он игнорирует сигналы этого типа и не обрабатывает их, ядро удаляет из таблицы процессов запись, соответствующую прекратившему существование потомку, и продолжает выполнение функции wait так, словно сигнала и не было. Ядро выполняет эти действия всякий раз, когда родительский процесс получает сигнал типа «гибель потомка», до тех пор, пока цикл выполнения функции wait не будет завершен и пока не будет установлено, что у процесса больше потомков нет. Тогда функция wait возвращает значение, равное -1. Разница между двумя способами запуска программы состоит в том, что в первом случае процесс-родитель ждет завершения любого из потомков, в то время как во втором случае он ждет, пока завершатся все его потомки.

Рисунок 7.17. Пример использования функции wait и игнорирования сигнала «гибель потомка»

В ранних версиях системы UNIX функции exit и wait не использовали и не рассматривали сигнал типа «гибель потомка». Вместо посылки сигнала функция exit возобновляла выполнение родительского процесса. Если родительский процесс при выполнении функции wait приостановился, он возобновляется, находит потомка, прекратившего существование, и возвращает управление. В противном случае возобновления не происходит; процесс-родитель обнаружит «погибшего» потомка при следующем обращении к функции wait. Точно так же и процесс начальной загрузки (init) может приостановиться, используя функцию wait, и завершающиеся по exit процессы будут возобновлять его, если он имеет усыновленных потомков, прекращающих существование.

В такой реализации функций exit и wait имеется одна нерешенная проблема, связанная с тем, что процессы, прекратившие существование, нельзя убирать из системы до тех пор, пока их родитель не исполнит функцию wait. Если процесс создал множество потомков, но так и не исполнил функцию wait, может произойти переполнение таблицы процессов из-за наличия потомков, прекративших существование с помощью функции exit. В качестве примера рассмотрим текст программы планировщика процессов, приведенный на Рисунке 7.18. Процесс производит считывание данных из файла стандартного ввода до тех пор, пока не будет обнаружен конец файла, создавая при каждом исполнении функции read нового потомка. Однако, процесс-родитель не дожидается завершения каждого потомка, поскольку он стремится запускать процессы на выполнение как можно быстрее, тем более, что может пройти довольно много времени, прежде чем процесс-потомок завершит свое выполнение. Если, обратившись к функции signal, процесс распорядился игнорировать сигналы типа «гибель потомка», ядро будет очищать записи, соответствующие прекратившим существование процессам, автоматически. Иначе в конечном итоге из-за таких процессов может произойти переполнение таблицы.

Рисунок 7.18. Пример указания причины появления сигнала «гибель потомков»

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

  • Как в mac os переименовать группу файлов
  • Как в mac os изменить программы по умолчанию
  • Как в mac os изменить вид папки
  • Как в mac os закрыть зависшую программу
  • Как в mac os закрыть все окна