10.6.3. Группы процессов
10.6.3. Группы процессов
Одной из главных целей Unix было создание набора простых инструментов, которые могут быть использованы вместе сложными способами (с помощью механизмов, подобных программным каналам). Большинство пользователей Linux делали нечто вроде следующего практического примера этой философии:
ls | grep "^[аА].*.gz" | more
Другое популярное средство, появившееся в Unix достаточно давно — управление заданиями (job control). Управление заданиями дает возможность пользователям прерывать текущее задание (известное как задание переднего плана (foreground task)) в то время, пока они уходят и делают на терминале что-то другое. Когда приостановленное задание представляет собой последовательность процессов, работающих вместе, система должна отслеживать, какие именно процессы должны быть приостановлены, когда пользователь желает приостановить задание переднего плана. Группы процессов позволяют системе видеть, какие процессы работают вместе, а потому должны управляться совместно средствами управления заданиями.
Процессы добавляются в группы с помощью setpgid().
int setpgid(pid_t pid, pid_t pgid);
pid — это процесс, который должен быть помещен в новую группу (0 обозначает текущий процесс), pgid — это идентификатор группы процессов, к которой должен принадлежать процесс pid, или 0, если процесс должен быть включен в новую группу процессов, чей pgid тот же, что и pid процесса. Подобно сеансам, лидер группы процессов — это процесс, чей pid совпадает в pgid группы.
Правила применения setpgid() несколько сложны.
1. Процесс может устанавливать группу для себя или одного из своих потомков. Он не может изменять группу для любого другого процесса в системе, даже если процесс, вызвавший setpgid(), имеет административные полномочия.
2. Лидер сеанса не может изменить свою группу.
3. Процесс не может быть перемещен в группу, чей лидер представляет другой сеанс, чем он сам. Другими словами, все процессы в группе должны относиться к одному и тому же сеансу.
Вызов setpgid() помещает вызывающий процесс в свою собственную группу и собственный сеанс. Это необходимо для того, чтобы гарантировать, что два сеанса не содержат процессы, принадлежащие к одной и той же группе.
Полный пример групп процессов будет приведен при обсуждении системы управления заданиями в главе 15.
Когда соединение с терминалом теряется, ядро посылает сигнал (SIGHUP; подробнее о сигналах рассказывается в главе 12) лидеру сеанса, содержащему группу процессов переднего плана данного терминала. Обычно это командная оболочка. Это позволит оболочке безусловно прерывать пользовательские процессы, извещая их о том, что пользователь выходит из системы (обычно посредством SIGHUP), либо выполнить некоторые другие действия (или бездействие). Хотя это все может показаться усложненным, это дает возможность лидеру группы сеанса принимать решения о том, как управлять закрывающимися терминалами, вместо того, чтобы возлагать эту обязанность на ядро. Это также дает возможность администраторам гибко управлять политиками пользовательских учетных записей.
Определение группы процесса может быть выполнено просто, с помощью функций getpgid() и getpgrp().
pid_t getpgid(pid_t pid) Возвращает pgid процесса pid. Если pid равен 0, возвращается pgid текущего процесса. Для вызова не требуется никаких специальных полномочий. Любой процесс может определять группу, к которой принадлежит любой другой процесс. pid_t getpgrp(void) Возвращает pgid текущего процесса pid (эквивалентно getprgid(0))