Лабораторная работа №4

 Процессы и задания

 

Процессы

Наряду с файлом понятие процесса является важнейшим в концепции открытых операционных систем. Процесс - это обладающая уникальным идентификатором единица исполняемого кода в памяти.

Подавая простую команду из оболочки, оператор дает ОС указание запустить другой процесс. В ходе исполнения процесс может порождать другие процессы и проходить целый ряд состояний. Сама оболочка также является процессом, порожденным, как правило, процессом регистрации в системе, который, в свою очередь, как правило, порождается особым инициализационным процессом.

Подобно файлам, процессы в своем отношении друг к другу могут быть представлены в виде иерархии (дерева). В отличие от иерархии файлов, ребра этого дерева представляют не отношения вложенности, но отношения порождения ("родитель - ребенок"). Процесс не может появиться в системе иначе, нежели будучи порожденным другим процессом, за исключением "корневого" процесса, запускаемого самим ядром при загрузке системы. Само ядро не является процессом.

Исследовать процессы можно стандартной командой ps. Поданная без параметров, она выводит информацию о текущей оболочке и порожденных ею процессах.

В выводе присутствуют четыре колонки:

·        PID - это уникальный для системы идентификатор процесса (он устанавливается при порождении процесса и сохраняется неизменным до его завершения),

·        TTY - терминал, с которого запущен процесс,

·        TIME - время процесса (сумма квантов процессорного времени, потребленного процессом на момент "снимка" его состояния),

·        CMD - команда, подача которой привела к порождению процесса.

В данном случае получена информация о двух процессах: оболочке bash и внешней команде ps.

Команда ps выводит информацию обо всех процессах в системе (Для обычного пользователя предоставление информации о чужих процессах может быть ограничено по соображениям безопасности).

Для наглядности представления можно использовать ключ "-А" вместе с ключом
"
-l" ("эль"), задающим "длинный" формат вывода, и ключом "", представляющим отношения между процессами отступами в поле CMD.

 

 

F  S  UID  PID  PPID  C  PRI  NI  ADDR  SZ   WCHAN   TTY    TIME   CMD

4  S    0      1        0       3   75    0        ¾    328    schedu        ?     00:00:04  init

4  S    0     759     1       0   76    0        ¾    575    wait4          ?     00:00:00     login

4  S  500   765   759     0   75    0        ¾   1061   wait4         tty1  00:00:00        bash

0  R  500   798   765     0   80    0        ¾    764      ¾            tty1  00:00:00           ps

4  S    0     760     1       0   82    0        ¾    322    schedu       tty2  00:00:00     mingetty


 

Несколько иной набор параметров процесса можно получить, использовав вместо ключа "-l" ключ "-w", a ключ "-о" позволяет вывести для каждого процесса произвольный набор параметров из числа поддерживаемых системой (указав их мнемонику в качестве аргумента этого ключа).

Стандартом определены пятнадцать параметров, к которым могут добавляться параметры, специфичные для конкретной системы.

UID - это идентификатор пользователя - владельца процесса. При использовании ключа "-l" идентификатор выводится в числовом виде, при ключе "-w" числовому идентификатору соответствует символический идентификатор. Числовой идентификатор 0 всегда соответствует главному пользователю "root".

Обычно UID наследуется от процесса-родителя. Исключение составляют процессы-оболочки, запускаемые программой регистрации, - их UID соответствует идентификатору зарегистрировавшегося пользователя, хотя UID самой программы регистрации - 0.

Еще одно исключение - процессы, порожденные запуском программы из файла с установленным битом SUID. Их UID соответствует не породившему их процессу, а владельцу исполняемого файла. SUID (и подобный ему бит GUID) - это мощный инструмент обхода системы распределения полномочий в ОС, поскольку позволяет пользователю запускать процессы с полномочиями выше собственных (в том числе с полномочиями главного пользователя). Установить SUID бит может только главный пользователь. В аккуратно построенной и администрируемой системе количество программ с установленным SUID (и/или GUID) битом минимально.

PID - это уникальный идентификатор процесса, a PPID - идентификатор его родителя. Существует соответствие между PPID различных процессов и расположением их в сформированном ключом "-Н" "дереве".

TIME - время процесса - это совокупное количество процессорного времени, потраченного на выполнение этого процесса за время его существования.

S - это состояние процесса. Запущенный процесс может находиться в одном из четырех стандартных состояний: "R" (выполняемый), "S" (ожидающий ввода-вывода), "Т" (приостановленный), "Z" ("зомбированный", уже завершенный, но не успевший сообщить об этом процессу-родителю).

 

Управление заданиями и сигнализация процессов

В среде стандартной оболочки и команд открытой ОС запустить бесконечный процесс можно, введя команду (while   :;   do   :;   done  ), запускающую бесконечный цикл в подчиненном экземпляре оболочки:

 [user@localhost user]$ (while :; do :; done)

Если все сделано правильно, то сценарий сам по себе уже не остановится никогда (до разгрузки системы). Приглашения оболочки тоже не последует, поэтому даже не будет возможности выйти из системы.

Справиться с этой ситуацией поможет клавиатурная комбинация Ctrl+C. Она не отображается на экране, но после ее нажатия оболочки дает приглашение и при помощи команды ps можно убедится, что никаких процессов, кроме самой оболочки и ps, под этой оболочкой не выполняется.

         

Ctrl+C побуждает драйвер терминала отправить сигнал нормального завершения выполняемому процессу (в данном случае подчиненной оболочке).

Ctrl+Z побуждает драйвер терминала отправить выполняемому процессу другой сигнал – приостановки:

После нажатия Ctrl+Z оболочка выдает сообщение, состоящее из числа в квадратных скобках, слова "остановлен" и введенной ранее команды.

Число в квадратных скобках - это номер задания. Заданием является любая начавшая выполняться простая команда.

Состояние соответствующего процесса (колонка "S" в выводе ps -l (эль)) обозначено буквой "Т", означающей, что процесс остановлен. Задание, соответствующее такому процессу, также называется остановленным.

Возобновить исполнение задания можно двумя способами:

fg возобновляет выполнение задания на переднем плане,

bg - на заднем плане (или в фоновом режиме).

В некоторых ОС понятие переднего и заднего планов выполнения было связано с приоритетами заданий или с выполнением одного из них в режиме "реального времени". В открытых ОС понятие приоритета и понятие плана выполнения взаимонезависимы. Заданием переднего плана называется задание завершения ведущего процесса (первого процесса, запущенного подачей команды), которого ожидает оболочка перед выводом очередного приглашения и которое может свободно выводить данные на управляющий терминал и вводить их с терминала.

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

В примере запущен сценарий "цикл", остановленный нажатием Ctrl+Z, затем возобновлено его выполнение на переднем плане командой fg, снова остановлено и затем возобновлено на заднем плане командой bg. После этого получено приглашение и введена команда ps -l, показывающая соответствующий выполнению сценария процесс bash (PID 2765) с состоянием "R" ("выполняемый").

Нажатие клавиатурных комбинаций Ctrl+C и Ctrl+Z всегда вызывает передачу сигнала заданию переднего плана. Заданию заднего плана передавать сигнал можно только явно, для чего служит команда kill. Указание в качестве ее единственного аргумента идентификатора процесса приводит к тому, что процессу передается сигнал "нормально завершиться" (это соответствует нажатию Ctrl+C для задания переднего плана):

Подача команды kill с ключом "-s" и идентификатором сигнала в качестве параметра этого ключа позволяет подать процессу произвольный сигнал. Стандартом определены восемь сигналов:

Реализация может предусматривать большее их количество. Практически во всех системах реализован сигнал SIGSTOP, его отправка процессу переднего плана большинством современных оболочек осуществляется нажатием Ctrl+Z.

На пользовательском уровне применяются обычно сигналы SIGTERM и SIGKILL. Отличие их в том, что при получении первого из них процесс по возможности завершается "чисто": сбрасывает содержимое внутренних буферов в файлы и закрывает их, а второго - завершается немедленно. Второй используется обычно для "убиения" процесса, выполняющего ошибочную программу.

До сих пор мы отправляли сигналы по собственной инициативе. Отправляющим процессом выступали оболочка (при передаче сигналов процессу переднего плана нажатием клавиш) или команда kill. Но передача сигналов (межпроцессная коммуникация) может осуществляться между любыми процессами и является широко используемым в системном и прикладном программировании механизмом ОС. Как и при доступе к файлам, при доступе к процессам ОС руководствуется системой распределения полномочий. Стандартное поведение проще, чем в случае с файлами: процесс, запущенный обычным пользователем (не главным пользователем), может сигнализировать процессу, запущенному тем же пользователем, и не может сигнализировать процессу, которым "владеет" другой пользователь. Реализацией может быть определено более сложное поведение. Программа может переопределить смысл сигналов, которые получает процесс (в частности, отменить завершение процесса), за исключением сигнала SIGKILL. Все стандартные команды ОС обрабатывают сигналы стандартным образом.

Если не удается завершить запущенный процесс подачей команды kill -s SIGKILL, значит, в системе возникли очень серьезные неполадки.

Также можно столкнуться с ситуацией, когда программа переопределяет SIGINT, SIGSTOP и входит в бесконечный цикл (или ожидает события, наступления которого в обозримом будущем не предвидится). Запустив такую программу на переднем плане, невозможно завершить ее нажатием Ctrl+C или приостановить нажатием Ctrl+Z, а подать SIGKILL командой kill также будет невозможно, поскольку оболочка ожидает завершения процесса переднего плана.

Простого выхода из этой ситуации нет, но обычно можно зарегистрироваться на другом терминале и "убить" процесс командой kill -s SIGKILL.

 

Сложные команды и задания

Чтобы запустить задание на заднем плане, не обязательно запускать его на переднем плане, приостанавливать и возобновлять командой bg. Можно воспользоваться символом завершения команды "&" (читается - "амперсенд").

 Использование символа завершения "&" позволяет ввести в одной строке более одной команды (и, соответственно, запустить более одного задания), разделенных этим символом. Список заданий можно получить командой jobs.

Знак "+" после номера задания обозначает "текущее" задание, то есть задание, которым можно управлять командами bg и fg без аргументов. Знаком "-" помечено "предыдущее" задание (которое станет текущим по завершению текущего). При переводе задания переднего плана на задний или запуске нового задания текущее задание (если оно есть) становится "предыдущим", а вновь запущенное - текущим.

Если нужно возобновить исполнение задания на переднем или заднем плане, или перевести задание на передний план, можно воспользоваться командами fg и bg, задав им аргумент, состоящий из "%" ("процент"), и следующим за ним слитно номером задания.

Другим символом завершения команды, также позволяющим подать более одной команды и инициировать более одного задания одной строкой, является ";" (точка с запятой). Команда, завершенная этим символом, будет выполняться на переднем плане, а последующие команды (задания) будут выполняться после ее завершения.

При подаче сложных команд (команд, включающих в себя более одной команды) их можно группировать с использованием круглых скобок. Сгруппированные скобками команды (вне зависимости от использованного символа завершения) образуют группу команд, выполняемых как одно задание.

Кроме того, группировка бывает полезна, чтобы передать значение переменной сразу всем командам или перенаправить ввод и/или вывод всех команд.

Механизм управления заданиями (являющийся позднейшей добавкой к концепции открытых систем) чрезвычайно полезен при выполнении сложных работ с алфавитно-цифрового терминала. Сегодня операторы предпочитают при возможности запускать разные программы в разных окнах виртуальных терминалов в графической среде. Тем не менее полезно хотя бы в общих чертах представлять, что это такое.

Существуют такие символы завершения команды "&&" и "||". Их действие связано с понятием кода завершения, возвращаемого каждой командой. Код завершения определяется программой, но обычно успешно выполнившаяся команда возвращает код "О" (ноль), а выполнившаяся с ошибкой - числовое значение кода ошибки. Явную работу с кодами завершения мы обсудим при введении элементов программирования оболочки, а здесь лишь упомянем, что символ завершения "&&" означает, что заданную за ним команду следует выполнить только в случае, если указанная перед ним команда выполнилась успешно, а символ "||" - наоборот, что "правую" команду следует выполнить только при ошибочном завершении "левой"

 

[Курс] [Помощь]