Операционная система UNIX
Шрифт:
Идентификатор родительского процесса Parent Process ID (PPID)
Идентификатор процесса, породившего данный процесс.
Приоритет процесса (Nice Number)
Относительный приоритет процесса, учитываемый планировщиком при определении очередности запуска. Фактическое же распределение процессорных ресурсов определяется приоритетом выполнения, зависящим от нескольких факторов, в частности от заданного относительного приоритета. Относительный приоритет не изменяется системой на всем протяжении жизни процесса (хотя может быть изменен пользователем или администратором) в отличие от приоритета выполнения, динамически обновляемого ядром.
Терминальная
Терминал или псевдотерминал, ассоциированный с процессом, если такой существует. Процессы-демоны не имеют ассоциированного терминала.
Реальный (RID) и эффективный (EUID) идентификаторы пользователя
Реальным идентификатором пользователя данного процесса является идентификатор пользователя, запустившего процесс. Эффективный идентификатор служит для определения прав доступа процесса к системным ресурсам (в первую очередь к ресурсам файловой системы). Обычно реальный и эффективный идентификаторы эквивалентны, т.е. процесс имеет в системе те же права, что и пользователь, запустивший его. Однако существует возможность задать процессу более широкие права, чем права пользователя путем установки флага SUID, когда эффективному идентификатору присваивается значение идентификатора владельца исполняемого файла (например, администратора).
Реальный (RGID) и эффективный (EGID) идентификаторы группы
Реальный идентификатор группы равен идентификатору первичной или текущей группы пользователя, запустившего процесс. Эффективный идентификатор служит для определения прав доступа к системным ресурсам по классу доступа группы. Так же как и для эффективного идентификатора пользователя, возможна его установка равным идентификатору группы владельца исполняемого файла (флаг SGID).
Команда ps(1) (process status) позволяет вывести список процессов, выполняющихся в системе, и их атрибуты:
Более подробное описание полей вывода команды ps(1) приведено далее в разделе "Основные утилиты UNIX".
Жизненный путь процесса
Процесс в UNIX создается системным вызовом fork(2). Процесс, сделавший вызов fork(2) называется родительским, а вновь созданный процесс — дочерним. Новый процесс является точной копией породившего его процесса. Как это ни удивительно, но новый процесс имеет те же инструкции и данные, что и его родитель. Более того, выполнение родительского и дочернего процесса начнется с одной и той же инструкции, следующей за вызовом fork(2). Единственно, чем они различаются — это идентификатором процесса PID. Каждый процесс имеет одного родителя, но может иметь несколько дочерних процессов.
Для запуска задачи, т.е. для загрузки новой программы, процесс должен выполнить системный вызов exec(2). При этом новый процесс не порождается, а исполняемый
В UNIX запуск на выполнение новой программы часто связан с порождением нового процесса, таким образом сначала процесс выполняет вызов fork(2), порождая дочерний процесс, который затем выполняет exec(2), полностью замещаясь новой программой.
Рассмотрим эту схему на примере.
Допустим, пользователь, работая в командном режиме (в командном интерпретаторе shell) запускает команду ls(1). Текущий процесс (shell) делает вызов fork(2), порождая вторую копию shell. В свою очередь, порожденный shell вызывает exec(2), указывая в качестве параметра имя исполняемого файла, образ которого необходимо загрузить в память вместо кода shell. Код ls(1) замещает код порожденного shell, и утилита ls(1) начинает выполняться. По завершении работы ls(1) созданный процесс "умирает". Пользователь вновь возвращается в командный режим. Описанный процесс представлен на рис. 1.5. Мы также проиллюстрируем работу командного интерпретатора в примере, приведенном в главе 2.
Рис. 1.5. Создание процесса и запуск программы
Если сделать "отпечаток" выполняемых процессов, например командой ps(1), между указанными стадиями, результат был бы следующим:
Пользователь работает в командном режиме:
Пользователь запустил команду ls(1), и shell произвел вызов fork(2):
Порожденный shell произвел вызов exec(2):
Процесс ls(1) завершил работу:
Описанная процедура запуска новой программы называется fork-and-exec.
Однако бывают ситуации, когда достаточно одного вызова fork(2) без последующего exec(2). В этом случае исполняемый код родительского процесса должен содержать логическое ветвление для родительского и дочернего процессов [9] .
9
Такое ветвление можно организовать на основании значения, возвращаемого системным вызовом fork(2). Для родительского процесса fork возвращает идентификатор созданного дочернего процесса, а дочерний процесс получает значение, равное 0. Подробнее эти вопросы будут рассмотрены в главе 2.