Жизненный цикл процесса
Как было отмечено ранее, процессы создаются другими процессами. Когда процессу требуется создать дочерний процесс, используется системный вы- зов fork().
Предположим, что пользователь выполнил в оболочке команду ps -f, желая получить список процессов, запущенных на данном виртуальном терминале. В таком случае ps -f является дочерним процессом оболочки. Пример 5.6 демонстрирует, что команда ps -f является дочерним процессом оболочки: PPID команды ps -f 1751 соответствует PID оболочки.
Пример 5.6. Идентификаторы дочернего процесса |
$ ps -f | ||||||
UID | PID | PPID | C STIME | TTY | TIME | CMD |
user1 | 0 21:01 | pts/0 | 00:00:00 | bash | ||
user1 | 0 21:32 | pts/0 | 00:00:00 | ps -f |
Команда ps -f будет подробнее рассмотрена далее, сейчас нам необходимо разобраться в том, каков был жизненный цикл процесса.
Когда пользователь ввел в командной строке команду ps -f, эта команда бы- ла проверена оболочкой bash, не является ли она встроенной. Так как эта ко- манда не является встроенной, для ее выполнения оболочка произвела сис- темный вызов fork().
Системный вызов fork() приводит к тому, что ядро копирует адресное про- странство процесса, произведшего этот вызов, в свободное адресное про- странство в памяти. Начиная с этого момента, в системе имеются два совер- шенно одинаковых процесса bash. В обоих процессах выполнение производится с одной и той же инструкции, следующей после fork().
При создании процесса ядро назначает ему уникальный идентификатор про- цесса PID. Так и сейчас, для копии родительской оболочки — дочернего процесса bash, в нашем случае, система назначила PID 1870, а PPID новой оболочки соответствует PID породившей ее оболочки — 1751.
Итак, в настоящий момент в системе имеются два одинаковых процесса bash. Но требовалось получить процесс команды ps -f. Поэтому в дочер- нем процессе bash должен быть произведен системный вызов класса exec() (см. man 3 exec), который позволяет загрузить программу /bin/ls и поместить прочитанный исполняемый код в адресное пространство до- чернего процесса.
В то же время родительский процесс bash должен быть приостановлен с по- мощью системного вызова wait(), ожидающего сигнала о завершении рабо- ты дочернего процесса. До тех пор, пока этот сигнал получен не будет, роди- тельский процесс bash не может продолжить работу.
Как же отличить родительский и дочерний процессы bash для того, чтобы определить, в каком из них надо вызвать exec(), а в каком — wait()? Их можно различить с помощью анализа значения, возвращаемого функцией fork(). Она возвращает PID дочернего процесса. Родительский процесс bash породил дочерний процесс, и, следовательно, fork() возвратил PID дочерне- го процесса. В порожденном процессе fork() возвращает 0.
После вызова exec() дочерний процесс уже не является процессом bash — он выполняет инструкции команды ps. Родительский процесс ждет заверше- ния дочернего процесса.
После того как команда ps -f завершает свою работу системным вызовом exit(), ее адресное пространство освобождается. Родительский процесс bash, который с помощью системного вызова wait() ожидал завершения ра- боты дочернего процесса, продолжит после этого свою работу.
Нормальный жизненный цикл процесса в системе может быть нарушен вследствие наступления какого-либо события. Например, процесс может по- лучить сигнал от другого процесса, который может привести к его прежде- временной остановке.
Информация о дочерних процессах в таблице процессов может быть важна для родительского процесса. Поэтому информация о них не стирается из таб- лицы процессов до вызова родительским процессом функции wait() (см. man 2 wait).
Возможна ситуация, когда дочерний процесс уже завершил свою работу, а родительский процесс не произвел еще системного вызова wait(). В таком случае информация об уже несуществующем дочернем процессе сохраняется в таблице процессов, т. к. эта информация может потребоваться родитель- скому процессу. Запись в таблице о завершившемся дочернем процессе по- мечается как defunct или, иначе, процесс-зомби (zombie).
Дата добавления: 2015-06-12; просмотров: 647;