Группы и сеансы
Группы и сеансы
После создания процесса ему присваивается уникальный идентификатор, возвращаемый системным вызовом fork(2) родительскому процессу. Дополнительно ядро назначает процессу идентификатор группы процессов (process group ID). Группа процессов включает один или более процессов и существует, пока в системе присутствует хотя бы один процесс этой группы. Временной интервал, начинающийся с создания группы и заканчивающийся, когда последний процесс ее покинет, называется временем жизни группы. Последний процесс может либо завершить свое выполнение, либо перейти в другую группу.
Многие системные вызовы могут быть применены как к единичному процессу, так и ко всем процессам группы. Например, системный вызов kill(2) может отправить сигнал как одному процессу, так и всем процессам указанной группы. Точно так же функция waitpid(2) позволяет родительскому процессу ожидать завершения конкретного процесса или любого процесса группы.
Каждый процесс, помимо этого, является членом сеанса (session), являющегося набором одной нескольких групп процессов. Понятие сеанса было введено в UNIX для логического объединения процессов, а точнее, групп процессов, созданных в результате регистрации и последующей работы пользователя в системе. Таким образом, термин "сеанс работы" в системе тесно связан с понятием сеанса, описывающего набор процессов, которые порождены пользователем за время пребывания в системе.
Процесс имеет возможность определить идентификатор собственной группы процессов или группы процесса, который является членом того же сеанса. Для этого используются два системных вызова: getpgrp(2) и getpgid(2):
#include <sys/types.h>
#include <unistd.h>
pid_t getpgrp(void);
pid_t getpgid(pid_t pid);
Аргумент pid, который передается функции getpgid(2), адресует процесс, идентификатор группы которого требуется узнать. Если этот процесс не принадлежит к тому же сеансу, что и процесс, сделавший системный вызов, функция возвращает ошибку.
Системный вызов setpgid(2) позволяет процессу стать членом существующей группы или создать новую группу.
#include <sys/types.h>
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
Функция устанавливает идентификатор группы процесса pid равным pgid. Процесс имеет возможность установить идентификатор группы для себя и для своих потомков (дочерних процессов). Однако процесс не может изменить идентификатор группы для дочернего процесса, который выполнил системный вызов exec(2), запускающий на выполнение другую программу.
Если значения обоих аргументов равны, то создается новая группа с идентификатором pgid, а процесс становится лидером (group leader) этой группы. Поскольку именно таким образом создаются новые группы, их идентификаторы гарантированно уникальны. Заметим, что группа не удаляется при завершении ее лидера, пока в нее входит хотя бы один процесс.
Идентификатор сеанса можно узнать с помощью функции getsid(2):
#include <sys/types.h>
#include <unistd.h>
pid_t getsid(pid_t pid);
Как и в случае с группой, идентификатор pid должен адресовать процесс, являющийся членом того же сеанса, что и процесс, вызвавший getsid(2). Заметим, что эти ограничения не распространяются на процессы, имеющие привилегии суперпользователя.
Вызов функции setsid(2) приводит к созданию нового сеанса:
#include <sys/types.h>
#include <unistd.h>
pid_t setsid(void);
Новый сеанс создается лишь при условии, что процесс не является лидером какого-либо сеанса. В случае успеха процесс становится лидером сеанса и лидером новой группы.
Понятия группы и сеанса тесно связаны с терминалом или, точнее, с драйвером терминала. Каждый сеанс может иметь один ассоциированный терминал, который называется управляющим терминалом (controlling terminal), а группы, созданные в данном сеансе, наследуют этот управляющий терминал. Наличие управляющего терминала позволяет ядру контролировать стандартный ввод/вывод процессов, а также дает возможность отправить сигнал всем процессам ассоциированной с терминалом группы, например, при его отключении. Типичным примером является регистрация и работа пользователя в системе. При входе в систему терминал пользователя становится управляющим для лидера сеанса (в данном случае для командного интерпретатора shell) и всех процессов, порожденных лидером (в данном случае для всех процессов, которые запускает пользователь из командной строки интерпретатора). При выходе пользователя из системы shell завершает свою работу и таким образом отключается от управляющего терминала, что вызывает отправление сигнала SIGHUP всем незавершенным процессам текущей группы. Это гарантирует, что после завершения работы пользователя в системе не останется запущенных им процессов.[26]
Данный текст является ознакомительным фрагментом.