Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Акуленок_часть1.doc
Скачиваний:
41
Добавлен:
13.11.2019
Размер:
1.43 Mб
Скачать

3.4.7. Идентификатор терминальной группы

Еще один способ группирования – объединение процессов в терминальную группу. Члены группы получают в качестве атрибута идентификатор терминальной группы TGID, который равен значению PID лидера этой группы. В качестве лидера выступает процесс, который открыл терминал. Управляющий терминал используется для передачи через управляющий процесс (т. е. процесс–лидер) сигналов для всех процессов – членов группы. Сигналы вырабатываются при нажатии определенных клавиш на клавиатуре. Следует отметить, что каждый пользователь, входящий в систему по login, обязательно порождает новые процессы. При этом каждый процесс в контексте пользователя имеет один и тот же идентификатор пользователя UID. Соответствие между UID и login–именем пользователя фиксируется в файле /etc/passwd. Пользователи получают различные привилегии. Имеются суперпользователи с неограниченными возможностями. Процесс суперпользователя (superuser) имеет UID, равный 0, а остальные – целые положительные числа, отличные от 9.

3.5. Иерархия процессов

Процессы образуют иерархические отношения между собой. Ядро предоставляет каждому процессу средства дублирования самого себя с целью создания новых процессов. Существуют понятия «процесс–отец» или родительский процесс и «процесс–сын» или дочерний процесс (child process). Процесс может иметь только одного «родителя», но порождать много «детей», и их отношения лучше всего выражает родственное древо. К примеру, рис. 3.3 показывает отношения процессов P1, Р2, РЗ, Р4, Р5 и P6 (P – это обозначение процесса).

В этом графе существуют следующие отношения:

Р1 порождает два процесса: Р2 и Р4. При этом P1 является «отцом», а Р2 и Р4 являются его «сыновьями».

P2 создает РЗ. При этом Р2 является «родителем» РЗ, а РЗ соответственно его «сыном» и «потомком» P1.

P4 является «родителем» Р5 и Р6; Р5 и Р6 – соответственно «детьми» Р4.

Рис. 3.3. Иерархия процессов

P1 является «дедушкой» P3, Р5 и Р6, Р3, Р5 и Р6 – «внуки» P1. Р3, Р5 и Р6 не имеют порожденных процессов.

3.6. Взаимодействие процессов

«Процесс–сын» наследует все свойства «процесса–отца», включая переменные окружения, текущий рабочий директорий, открытые файлы.

Любой процесс в UNIX порождается с помощью системного вызова fork(), поэтому часто говорят о ветвлении (fork – ветвь). После выполнения fork() оба процесса продолжают выполнение с одной и той же точки.

Любой процесс может завершиться по собственной инициативе с помощью системного вызова exit (status).

3.6.1. «Отцы», «дети», «сироты», «зомби»

Операционная система UNIX, являясь в своей основе средством управления процессами, сама по себе может рассматриваться как система параллельных взаимодействующих процессов с древовидной структурой. Общий прародитель всех процессов в системе – процесс init, находящийся в вершине генеалогического древа. Этот процесс порождается особым образом и далее постоянно присутствует в системе. Все другие процессы порождаются в системе по унифицированной схеме с помощью системного вызова fork().

Сразу после обработки системного вызова fork() происходит установление двусторонней связи между «процессом–отцом» и «процессом–сыном». «Сын» при этом наследует все свойства «отца». Однако существование нового, порожденного процесса как точной копии другого не имеет никакого смысла. Поэтому почти всегда «сын» заменяет программный код «отца» на свой собственный программный код. Эго возможно с помощью системного вызова ехес().

«Процесс–отец» ожидает окончания исполнения «процесса–сына», используя системный вызов wait().

Что происходит в случае завершения процесса? Если процесс издает системный вызов exit(), то он, выражаясь языком пользователей UNIX, становится «процессом–самоубийцей» и порождает в связи со своей смертью целый ряд проблем.

Ведь каждый из завершивших свой жизненный путь процессов имеет своего «родителя», но одновременно он может быть «родителем» других процессов. Поэтому могут остаться «сироты», судьбу которых надо как–то решать. Здесь имеется несколько вариантов:

  1. Вариант нормального окончания.

«Процесс–отец» выдает системный вызов wait() и ждет, когда «процесс–сын» завершит свое выполнение по системному вызову exit(). Однако, если у «сына» были свои «процессы–дети», то чтобы они не остались «сиротами», происходит их «усыновление» прародителем всех процессов init. Главная работа ядра UNIX при этом заключается в переустановлении PPID у «процессов–сыновей». Он становится для них равным единице. Кроме того, всем процессам – членам группы рассылается соответствующий сигнал.

  1. Вариант «ненормального» окончания.

«Процecc–сын» выдает системный вызов exit(), когда существует его «отец» и «отец» не находится в состоянии ожидания wait(). В этом случае связь «отца» с «сыном» продолжает существовать, несмотря на то, что «сын» «умер». Слот «процесса–сына» в таблице процессов сохраняется, и поэтому такой не до конца уничтоженный процесс называют «зомби».

Удалить такой процесс можно только перезапуском операционной системы. Зомби в небольших количествах не представляют опасности, однако если их много, это может привести к переполнению таблицы процессов.

Элемент в системной таблице процессов сохраняется до тех пор, пока родительский процесс не выполнит системный вызов wait(), только после этого освобождается и элемент системной таблицы процессов.

  1. Вариант преждевременного выхода.

«Процесс–отец» заканчивается ранее своих «сыновей». В этом случае происходит реконфигурация генеалогического древа и все «процессы–сироты» перенаправляются постоянно действующему процессу init.