Завершение порожденного процесса. Системный вызов waitpid(). Сигнал SIGCHLD
В материалах семинаров 3–4 (раздел "Завершение процесса. Функция exit()") при изучении завершения процесса говорилось о том, что если процесс-ребенок завершает свою работу прежде процесса-родителя, и процесс-родитель явно не указал, что он не заинтересован в получении информации о статусе завершения процесса-ребенка, то завершившийся процесс не исчезает из системы окончательно, а остается в состоянии закончил исполнение (зомби-процесс) либо до завершения процесса-родителя, либо до того момента, когда родитель соблаговолит получить эту информацию.
Для получения такой информации процесс-родитель может воспользоваться системным вызовом waitpid() или его упрощенной формой wait(). Системный вызов waitpid() позволяет процессу-родителю синхронно получить данные о статусе завершившегося процесса-ребенка либо блокируя процесс-родитель до завершения процесса-ребенка, либо без блокировки при его периодическом вызове с опцией WNOHANG. Эти данные занимают 16 бит и в рамках нашего курса могут быть расшифрованы следующим образом:
- Если процесс завершился при помощи явного или неявного вызова функции exit(), то данные выглядят так (старший бит находится слева) :
- Если процесс был завершен сигналом, то данные выглядят так (старший бит находится слева):
Каждый процесс-ребенок при завершении работы посылает своему процессу-родителю специальный сигнал SIGCHLD, на который у всех процессов по умолчанию установлена реакция "игнорировать сигнал". Наличие такого сигнала совместно с системным вызовом waitpid() позволяет организовать асинхронный сбор информации о статусе завершившихся порожденных процессов процессом-родителем.
Системные вызовы wait() и waitpid() Прототипы системных вызовов #include <sys/types.h> #include <wait.h> pid_t waitpid(pid_t pid, int *status, int options); pid_t wait(int *status); Описание системных вызовов Это описание не является полным описанием системных вызовов, а адаптировано применительно к нашему курсу. Для получения полного описания обращайтесь к UNIX Manual. Системный вызов waitpid() блокирует выполнение текущего процесса до тех пор, пока либо не завершится порожденный им процесс, определяемый значением параметра pid, либо текущий процесс не получит сигнал, для которого установлена реакция по умолчанию "завершить процесс" или реакция обработки пользовательской функцией. Если порожденный процесс, заданный параметром pid, к моменту системного вызова находится в состоянии закончил исполнение, то системный вызов возвращается немедленно без блокирования текущего процесса. Параметр pid определяет порожденный процесс, завершения которого дожидается процесс-родитель, следующим образом:
Параметр options в нашем курсе может принимать два значения: 0 и WNOHANG. Значение WNOHANG требует немедленного возврата из вызова без блокировки текущего процесса в любом случае. Если системный вызов обнаружил завершившийся порожденный процесс, из числа специфицированных параметром pid, то этот процесс удаляется из вычислительной системы, а по адресу, указанному в параметре status, сохраняется информация о статусе его завершения. Параметр status может быть задан равным NULL, если эта информация не имеет для нас значения. При обнаружении завершившегося процесса системный вызов возвращает его идентификатор. Если вызов был сделан с установленной опцией WNOHANG, и порожденный процесс, специфицированный параметром pid, существует, но еще не завершился, системный вызов вернет значение 0. Во всех остальных случаях он возвращает отрицательное значение. Возврат из вызова, связанный с возникновением обработанного пользователем сигнала, может быть в этом случае идентифицирован по значению системной переменной errno == EINTR, и вызов может быть сделан снова. Системный вызов wait является синонимом для системного вызова waitpid со значениями параметров pid = -1, options = 0. |
Используя системный вызов signal(), мы можем явно установить игнорирование этого сигнала (SIG_IGN), тем самым проинформировав систему, что нас не интересует, каким образом завершатся порожденные процессы. В этом случае зомби-процессов возникать не будет, но и применение системных вызовов wait() и waitpid() будет запрещено.