Процесс как динамическая структура может находиться в различных состояниях (схема является упрощенной):
Готовность
fork()
Выполнение
exit()
Зомби
wait()
Ожидает/
заблокирован
A
B
C
D
Новый процесс создается существующим с помощью системного вызова fork(), который возвращает нулевое значение дочернему процессу, а родительскому — PID дочернего процесса.
Далее дочерний процесс обычно запускает новую программу, используя один из системных вызовов семейства exec(). При этом у созданного процесса замещается область кода, устанавливаются область данных и стек в исходное состояние выполнения программы.
Когда определены все данные и инструкции для процесса, но он еще не получил доступ к процессору, считается, что процесс находится в состоянии готовности.
Переход в состояние выполнения (переход A) характеризуется выбором процесса планировщиком. В регистры процессора и в память помещается контекст процесса и начинается выполнение определенной контекстом программы.
Перейти обратно из состояния выполнения в состояние готовности (переход B) возможен в двух случаях:
— временной отрезок, отведенный планировщиком закончился; процесс опять помещается в очередь выполнения и становится неактивным;
— процесс приостановлен, но остается активным;
Переход из состояния выполнения в состояние ожидания/блокировки (переход C) происходит, когда процесс чего-то ожидает (освобождения ресурса, ввода данных и пр.).
Из состояния ожидания/блокировки в состояние готовности (переход D) процесс переходит, когда он получает сигналы, либо когда ресурс становится доступным.
Процесс завершает работу с помощью системного вызова exit(). В результате освобождаются ресурсы, занимаемые процессом, но запись в таблице процессов остается — процесс превращается в зомби. Удаление процесса из таблицы процессов должно быть подтверждено родителем с помощью системного вызова wait(), возвращающего код завершения потомка. При этом возможны два случая:
— потомок завершается до родителя — потомок пребывает в состоянии зомби до тех пор, пока родитель не сделает системный вызов wait();
— родитель завершается до потомка — родителем назначается процесс init, т.е. PPID потомка устанавливается в 1. Вызов wait() будет производить процесс init.
Если по каким-то причинам родитель не выполнил вызов wait(), потомок будет находиться в состоянии зомби до завершения работы системы, занимая ресурсы только в виде записи в таблице процессов.