Лаб_ОС_10

advertisement
Лабораторная работа №10
Изучение процессов в ОС Unix
Цель: получить представление об иерархии процессов операционной
системы Unix и изучить возможности управления работой процессов.
1. Общие положения
1.1. Концепция процесса в UNIX
Стандарты UNIX, а именно IEEE Std 1003.1, 2004 Edition, определяют
процесс как «адресное пространство с одним или несколькими потоками,
выполняющимися в нем, и системные ресурсы, необходимые этим потокам».
Процессом можно считать любую выполняющуюся программу. Процесс
состоит из программного кода, данных, переменных (занимающих
системную память), открытых файлов (файловых дескрипторов) и
окружения. Обычно в системе UNIX процессы совместно используют код и
системные библиотеки, так что в любой момент времени в памяти находится
только одна копия программного кода.
Операционная система управляет процессами с помощью их
идентификаторов, PID, которые применяются как указатели в таблице
процессов. У таблицы ограниченный размер, поэтому число процессов,
поддерживаемых системой, ограничено. В первых системах UNIX оно
равнялось 256 процессам. Более современные реализации значительно
ослабили это ограничение и ограничены только объемом памяти, доступным
для формирования элемента таблицы процессов.
Рисунок 1- Состояния процесса в UNIX
Вывод командой ps столбца STAT предоставляет коды текущего состояния
процесса.
Таблица 1.
Код STAT
S
R
D
T
Z
N
S
+
l
<
Описание
Спящий. Обычно ждет появления события, такого как сигнал
или активизация ввода
Выполняющийся. Строго говоря "работоспособный", т.е. в
очереди на выполнение, либо выполняющийся, либо готовый к
выполнению
Непрерывно спящий (ожидающий). Обычно ждущий
завершения ввода или вывода
Остановленный. Обычно остановленный системой управления
заданиями командной оболочки или находящийся под
контролем отладчика
Умерший или процесс-зомби
Задача с низким приоритетом, "nice"
Ведущий процесс сеанса
Процесс в группе фоновых процессов
Многопотоковый процесс
Задача с высоким приоритетом
В операционных системах Linux и UNIX используется система приоритетов,
всего 40 уровней, начиная с -20 (наивысший приоритет) и заканчивая 19
(низший приоритет).
Процессы, запущенные обычными пользователями, обычно имеют приоритет
0.
Каждому процессу при запуске устанавливается определенный приоритет,
который имеет значение от -20 до +20, где +20 - самый низкий. Приоритет
нового процесса равен приоритету процесса-родителя.
Команда ps может показать приоритет процесса (например, значение nice или
NI) с помощью опции -l.
Команда nice показывает приоритет по умолчанию.
1.2. Процессы загрузки системы
С запуска процесса init начинается загрузка самой системы. Во времена
молодости в этом месте никаких подводных камней не наблюдалось. Если
ядро содержало подпрограммы для работы со всеми необходимыми
устройствами (так называемые "драйверы"), оно загружалось и запускало
init. Если ядру недоставало каких-то важных драйверов (например,
поддержки дискового массива) - оно не загружалось. Из положения
выходили просто: в ядро старались включить как можно больше драйверов.
Такое ядро называлось базовым (generic) и имело довольно внушительный
размер. Загрузив систему с базовым ядром, администратор обычно
пересобирал его: выбрасывал из специального файла-профиля драйверы
всех отсутствующих в системе устройств, быть может, добавлял новые (те,
что не нужны для загрузки, но необходимы для работы, например, звуковые)
и компилировал из исходных текстов новое, профильное ядро.
Совсем другие времена настали, когда изобрели и активно внедрили в Unix
загружаемые модули ядра. Модуль ядра - это часть ядра Unix, которую
можно добавлять и удалять во время работы системы. Модуль ядра - не
процесс, он работает в режиме супервизора и в таблице процессов не
регистрируется: это набор подпрограмм для работы с определенным
устройством, которые добавляются к возможностям ядра. При загрузке в
память модуль компонуется с ядром, образуя с ним одно целое.
Просмотреть список загруженных модулей можно командой lsmod, а
подгрузить модуль в память, добавив его к ядру, и удалить его оттуда командами insmod и rmmod соответственно.
Если в параметрах не указано иное, ядро считает, что init называется
/sbin/init. В стартовом виртуальном диске это обычно некоторый
простейший сценарий, а в полноценной системе у init другая задача: он
запускает все процессы. Если процессы запускает не он сам, то это делают
его потомки, так что все процессы Unix, кроме ядерных, происходят от init.
Полноценно загруженная Unix-система - не только login на виртуальной
консоли. Системе есть чем заняться и помимо идентификации пользователей.
Даже если компьютер не работает WWW-, FTP- или почтовым сервером для
"внешнего мира", себе самой и своим пользователям система предоставляет
множество услуг: отсылка заданий на печать и обеспечение их очереди,
запуск заданий по расписанию, проверка целостности и т.п. Набор утилит и
системных программ, предназначенных для предоставления таких услуг,
принято называть подсистемами или службами.
Как правило, системная служба организована так. Во время начальной
загрузки запускается в фоновом режиме программа, которая на протяжении
работы системы находится в таблице процессов, однако большей частью
бездействует, ожидая, когда ее о чем-нибудь попросят. Для того чтобы
попросить эту программу об услуге, которую она предоставляет,
используются утилиты, взаимодействующие с ней по специальному
протоколу. По аналогии с сократовским "даймонионом", который незримо
присутствует, по своей инициативе не делает ничего, не дает совершать
плохое и способствует хорошему, такую программу стали называть
"daemon". Не знакомые с творчеством Платона программисты-любители
частенько переименовывали ее в "demon" (демон).
Демон. Запускаемая в фоне программа, длительное время пребывающая в таблице
процессов. Обычно демон активизируется по запросу пользовательской программы, по
сетевому запросу или по наступлению какого-либо системного события.
В ранних версиях UNIX все, что нужно было запускать при старте системы,
вписывалось в файл inittab. Было довольно удобно в одном файле
указывать, какие именно демоны должны работать в системе, и в каком
порядке их запускать. Само поведение демона при запуске явно рассчитано
на использование в inittab по методу "wait": классический демон
запускается интерактивно, проверяя правильность конфигурационных
файлов и прочие условия работы, а затем самостоятельно уходит в фон
(делая fork() и завершая родительский процесс). Таким образом, init
ждет, пока демон работает интерактивно, а когда служба, возглавляемая этим
демоном, готова к работе, переходит к следующей строке inittab. Однако
часто бывает так, что автор демона не знает, какие именно условия
разработчики той или иной версии Unix сочтут пригодными для запуска. Для
этого ими создается стартовый сценарий, в котором запрограммирована
логика запуска и останова службы.
Стартовый сценарий - программа (обычно написанная на shell),
управляющая включением или выключением какого-нибудь свойства
системы. Это может быть запуск и остановка HTTP-сервера, активизация и
деактивизация сетевых настроек, загрузка модулей и настройка звуковой
подсистемы и т.п. Простейший стартовый сценарий обязан принимать один
параметр, значение которого может быть словом "start" для запуска
(включения) и "stop" для остановки (выключения). Если в определенном
дистрибутиве Unix принято решение, что стартовые сценарии должны
понимать и другие параметры, например "restart" (обычно "stop"+"start", но
не всегда) и "status" (для опроса состояния), это требование распространяется
на все стартовые сценарии. Единообразие позволяет, например, без труда
запускать и останавливать демоны, не выясняя, каков PID останавливаемого
процесса и какой именно сигнал ему следует послать.
Все стартовые сценарии служб, которыми может воспользоваться система,
принято хранить в каталоге /etc/rc.d/init.d (в некоторых дистрибутивах, для
совместимости со старыми версиями UNIX, используется /etc/init.d, иногда
это просто символьная ссылка на /etc/rc.d/init.d).
1.3. Запуск процессов и управление вводом-выводом
Каждый процесс (кроме системных) является результатом запуска
программы, хранящейся в файле на диске. Для запуска процесса следует
ввести путь к запускаемому файлу (относительный или абсолютный) в
командной строке shell. Если путь не указан, shell будет искать программу,
последовательно проверяя каталоги, указанные в переменной окружения
PATH. Найдя файл (файл должен иметь права на запуск), shell проверяет его
формат. Если файл является двоичным исполнимым файлом, то он
запускается. Если файл - текстовый, то анализируется его первая строка,
которая должна содержать путь к интерпретатору программы в виде:
#!/usr/bin/sh
или
#!/usr/local/bin/perl –w
В этом случае shell запускает указанный интерпретатор и передает ему имя
текстового файла для исполнения. Если строка с указанием интерпретатора
не найдена, то shell запускает свою копию, которая пытается исполнить файл
как последовательность команд командной строки.
Запуск в фоновом режиме
Если сама программа не предусматривает иное, процесс запускается в
интерактивном режиме, т.е. shell ожидает завершения процесса, прежде чем
вернуть приглашение командной строки. Для запуска процесса в фоновом
режиме, командную строку следует завершить символом '&' (амперсанд).
Обратите, внимание, что shell выдал номер процесса ls и сразу же вернул
приглашение командной строки. Тем не менее, команда ls, хотя и запущенная
в фоновом режиме, вывела данные как обычно на терминал, поскольку
стандартный вывод этой команды по-прежнему связан с терминалом. То же
касается и вывода в стандартную ошибку.
Сложнее обстоит дело, если процесс, запущенный в фоновом режиме
пытается считать данные со стандартного ввода. В этом случае, если shell
поддерживает управление заданиями, то процесс будет остановлен по
сигналу SIGTTIN и будет возобновлен после того, как пользователь
переведет его в интерактивный режим.
Запуск в режиме демона
Для запуска процесса в режиме демона, следует в начале командной строки
ввести префикс nohup, а в конце - амперсанд. При этом, если пользователем
не указано иное, стандартный вывод направляется в файл nohup.out в
текущем каталоге или в домашнем, если у пользователя нет прав записи в
текущий каталог.
Отличие фонового режима от демона заключается в том, что в режиме
демона процесс не связан с терминалом, следовательно, завершение сеанса
работы пользователя не приведет к завершению процесса.
Перенаправление вывода
В системе по-умолчанию всегда открыты три "файла" – stdin (клавиатура),
stdout (экран) и stderr (вывод сообщений об ошибках на экран). Эти, и
любые другие открытые файлы, могут быть перенаправлены. В данном
случае, термин "перенаправление" означает получить вывод из файла,
команды, программы, сценария или даже отдельного блока в сценарии и
передать его на вход в другой файл, команду, программу или сценарий.
С каждым открытым файлом связан дескриптор файла. Дескрипторы
файлов stdin, stdout и stderr -- 0, 1 и 2, соответственно. При открытии
дополнительных файлов, дескрипторы с 3 по 9 остаются незанятыми. Иногда
дополнительные дескрипторы могут сослужить неплохую службу, временно
сохраняя в себе ссылку на stdin, stdout или stderr. Это упрощает
возврат дескрипторов в нормальное состояние после сложных манипуляций с
перенаправлением и перестановками.
Команда перенаправления вывода
COMMAND_OUTPUT >
ls -lR > dir-tree.list
: > filename
> filename
COMMAND_OUTPUT >>
1>filename
1>>filename
2>filename
2>>filename
&>filename
2>&1
Описание
Перенаправление stdout (вывода) в файл.
Если файл отсутствовал, то он создется,
иначе -- перезаписывается.
Создает файл, содержащий список дерева
каталогов
Операция > усекает файл "filename" до
нулевой длины. Если до выполнения
операции файла не существовало, то
создается новый файл с нулевой длиной.
Символ : выступает здесь в роли место
заполнителя, не выводя ничего.
тот же результат, что и выше -- ": >", но
этот вариант неработоспособен в
некоторых командных оболочках.
Перенаправление stdout (вывода) в файл.
Создает новый файл, если он отсутствовал,
иначе -- дописывает в конец файла.
Перенаправление вывода (stdout) в файл
"filename".
Перенаправление вывода (stdout) в файл
"filename", файл открывается в режиме
добавления.
Перенаправление stderr в файл "filename".
Перенаправление stderr в файл "filename",
файл открывается в режиме добавления.
Перенаправление stdout и stderr в файл
"filename".
Перенаправляется stderr на stdout.
Сообщения об ошибках передаются туда
же, куда и стандартный вывод.
Допускается перенаправление нескольких потоков в один файл.
ls -yz >> command.log 2>&1
Сообщение о неверной опции "yz" в команде "ls" будет записано в файл
"command.log", поскольку stderr перенаправлен в файл.
Команда
cat /dev/null>file
обнуляет файл file (содержимое пустого по определению файла /dev/null
записывается в файл file).
1.4. Получение информации о процессах
Команда ps выводит различную информацию о запущенных процессах.
Запущенная без ключей, эта команда выводит сводку процессов, связанных с
терминалом, с которого ее запустили. Ключи позволяют а) выбрать
процессы, информацию о которых следует вывести; б) указать, какую
информацию о процессах выводить.
Основные ключи команды ps:
вывести информацию обо всех запущенных процессах;
пользователь – вывести информацию о процессах указанного
пользователя;
-f
"полный" листинг (см. таблицу ниже);
-l
"длинный" листинг (см. таблицу ниже);
-j
вывести идентификаторы группы процессов и сеанса.
-e
-u
Таблица 1. Поля вывода команды ps
Поле
S
Описание
Состояние процесса:
O - выполняется (On processor),
R - готов к запуску (Runnable),
S - находится в состоянии сна (Sleeping),
Z - зомби (Zombie),
T - остановлен (Stopped).
Ключи*
l
UID
Идентификатор пользователя, от имени которого запущен процесс (с
f,l
ключом -f выводится имя пользователя)
PID
PPID
PGID
SID
PRI
Идентификатор процесса
Идентификатор родительскогопроцесса
Идентификатор группы процессов
Идентификатор сеанса
Приоритет процесса (чем больше, тем ниже)
все
f,l
j
j
l
NI
Относительный приоритет (Nice Number)
Размер процесса в страницах (размер страницы можно узнать командой
SZ
pagesize)
STIME Время запуска процесса
TTY
Управляющий терминал ('?' - для демонов)
TIME Суммарное время, затраченное процессором на исполнение процесса
CMD
l
l
f
все
все
Имя процесса (с ключом -f выводятся первые 80 символов командной
все
строки)
*) - в колонке Ключи указано, какой ключ надо дать команде ps, чтобы
соответствующее поле появилось в выводе. Пометка "все" обозначает, что
поле выводится всегда, в том числе и при запуске команды без ключей.
Ключи -f, -l, -j можно использовать совместно для получения
комбинированного вывода.
Ключи -f, -l, -j не определяют, о каких процессах выводить данные , а
устанавливают только формат вывода. Для отбора процессов используйте
ключи -e, -u.
Команда ps имеет также ключ -o (буква "о"), параметром которого
является список полей вывода через запятую. Таким образом, можно выбрать
только необходимые поля, а также вывести дополнительные данные о
процессе, не перечисленные в таблице выше. Наименования полей для ключа
-o см. в справочнике man.
Команда pstree выводит процессы в форме дерева. Основным
преимуществом является то, что вы сразу можете увидеть родительские
процессы: если вам нужно уничтожить целую серию процессов, а они все
происходят от одного родителя, вы можете просто убить этот родительский
процесс. Вам придётся воспользоваться опцией -p для вывода PID всех
процессов и опцией -u для вывода имени пользователя, запустившего
процесс. Т.к. дерево зачастую довольно большое, вам потребуется запустить
pstree следующим образом:
pstree -up | less
При этом вы получите обзор всей структуры дерева процессов.
Команда ps делает моментальный снимок процессов в текущий момент. В
отличии от нее, команда top - динамически выводит состояние процессов и
их активность в реальном режиме времени.(Для выхода из нее можно нажать
клавишу Q).
В верхней части вывода отображается астрономическое время, время,
прошедшее с момента запуска системы, число пользователей в системе,
число запущенных процессов и число процессов, находящихся в разных
состояниях, данные об использовании ЦПУ, памяти и раздела подкачки.
Далее идет таблица, характеризующая отдельные процессы. Число строк,
отображаемых в этой таблице, определяется размером окна: сколько строк
помещается, столько и выводится.
Содержимое окна обновляется каждые 5 секунд. Список процессов может
быть отсортирован по используемому времени ЦПУ (по умолчанию), по
использованию памяти, по PID, по времени исполнения. Переключать
режимы отображения можно с помощью следующих клавиатурных команд:
<Shift>+<N> — сортировка по PID;
<Shift>+<A> — сортировать процессы по возрасту;
<Shift>+<P> — сортировать процессы по использованию ЦПУ;
<Shift>+<M> — сортировать процессы по использованию памяти;
<Shift>+<T> — сортировка по времени выполнения.
С помощью команды <K> можно завершить некоторый процесс (его PID
будет запрошен), а с помощью команды <R> можно переопределить
значение nice для некоторого процесса.
1.5. Изменение приоритетов процессов
Каждому процессу при запуске устанавливается определенный приоритет,
который имеет значение от -20 до +20, где +20 - самый низкий. Приоритет
нового процесса равен приоритету процесса-родителя. Для изменения
приоритета запускаемой программы существует команда nice. Пример ее
использования:
nice [- adnice] command [args]
где adnice — значение (от –20 до +19), добавляемое к значению nice
процесса-родителя. Отрицательные значения может устанавливать только
суперпользователь. Если опция adnice не задана, то по умолчанию для
процесса-потомка устанавливается значение nice, увеличенное на 10 по
сравнению со значением nice родительского процесса. Опция –n
используется для установки значения приоритета.
Пример: nice -n 19 dd
Команда renice служит для изменения значения nice для уже
выполняющихся процессов. Суперпользователь может изменить приоритет
любого процесса в системе. Другие пользователи могут изменять значение
приоритета только для тех процессов, для которых данный пользователь
является владельцем. При этом обычный пользователь может только
уменьшить значение приоритета. Поэтому процессы с низким приоритетом
не могут породить "высокоприоритетных детей".
Пример: renice +20 -u peter
процессы пользователя peter получат наименьший приоритет и не будут
затруднять работу процессов других пользователей.
1.6. Отправка сигналов процессам
Команда
kill -СИГНАЛ PID
отправляет процессу с идентификатором PID указанный сигнал. Сигнал
указывается либо в символьной форме (за вычетом приставки 'SIG'), либо в
виде номера сигнала. Например, "kill -HUP PID" и "kill -1 PID"
(цифра "один") - одно и то же. Список всех сигналов и их номеров можно
просмотреть командой kill -l (буква "эль"). По умолчанию, если
сигнал не указан, посылается сигнал SIGTERM (номер 15).
Идентификатор процесса можно узнать с помощью команды ps .
Пользователь может отправлять сигналы только к процессам, запущенным от
его имени.
Пример выполнения команды kill -l
1) SIGHUP
2) SIGINT
3) SIGQUIT 4) SIGILL 5) SIGTRAP
6)
SIGABRT
7) SIGBUS
8) SIGFPE
9) SIGKILL
10) SIGUSR1 11)
SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 17)
SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22)
SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM
27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
2. Порядок выполнения работы
Выполните в командной строке ОС семейства UNIX перечисленные ниже
действия. Протоколируйте процесс выполнения (с помощь скриншотов или
записывая команды) и представьте их в отчете.
1.
Просмотрите список всех загруженных модулей.
2.
Запустите процесс ls в фоновом режиме.
3.
Запустите процесс ls в режиме демона.
4.
Перенаправьте поток вывода команды ls в файл test и просмотрите его.
5.
Перенаправьте поток вывода команд «ls –l» и «ls –l prog» в файл test с
его дозаписью. Просмотрите этот файл
6.
Изучите список всех запущенных в вашей системе процессов.
7.
Определите, какой процесс истратил больше всего процессорного
времени.
8.
Определите, какой процесс занимает больше всего памяти.
9.
Определите, сколько демонов и зомби запущено в системе.
10. Определите количество свободной и используемой в системе памяти.
11. Получите дерево процессов.
12. Запустите два процесса (например, find и sort) в фоновом режиме (c
подавлением потоков вывода), и два (например, ps и cat) - в интерактивном.
find / 2>/dev/null | sort >/dev/null 2>&1 &
ps -ej | cat
Выпишите из листинга команды ps строки, относящиеся к четырем выше
указанным процессам. Найдите идентификаторы группы и сеанса для
каждого процесса, определите лидеров групп и сеанса.
Проверьте, работают ли запущенные процессы:
ps -fu ваш_пользователь
Закройте терминал. Вновь откройте и проверьте, какие процессы остались с
прошлого сеанса.
13.
Пошлите сигнал SIGTERM процессу find (если он еще работает, иначе
предварительно запустите его). Убедитесь, что find исчез из списка
процессов.
14. Пошлите какой-нибудь сигнал любому процессу, которым вы не
владеете.
15. Найдите номер процесса своего shellа и отправьте ему сигнал SIGHUP.
Контрольные вопросы
1.
Как происходит порождение процессов?
2.
Какие функции выполняет процесс init?
3.
Могут ли родственные процессы разделять общую память?
4.
Каким образом может быть порожден новый процесс? Какова
структура нового процесса?
5.
В каких состояниях может находиться процесс?
6.
Какими процессами в системе могут управлять пользователи?
7.
Для чего используется фоновый режим?
8.
Как можно перевести программу в фоновый режим?
9.
Какая информация о процессах выводится при использовании команды
ps?
10. Для чего используются сигналы в ОС UNIX?
11. В каких случаях следует принудительно завершить процесс?
3.
Download