Лабораторная работа 20
1. Цель работы: Ознакомиться на практике с понятием процесса в операционной системе. Приобрести опыт и навыки управления процессами в операционной системе Linux.
2. Краткие теоретические сведения
Устройство Linux: ядро и процессы
Главная, постоянно находящаяся в оперативной памяти, часть ОС Linux называется ядром (Kernel). Ядро ОС обрабатывает прерывания от устройств, выполняет запросы системных процессов и пользовательских приложений, распределяет виртуальную память, создает и уничтожает процессы, обеспечивает многозадачность средством переключения между ними, содержит драйверы устройств, обслуживает файловую систему (см. рис. 1).
Начальная загрузка системы состоит в том, что файл с образом ядра считывается в оперативную память, начиная с нулевого адреса. Этот файл находится в каталоге /boot и называется vmlinuz-x.y.z, где x.y.z — это номер версии ядра. На текущий момент большинство дистрибутивов основано на ядре версии 2.4, хотя уже вышло ядро 2.6 и кое- где еще встречается версия 2.2.
В UNIX-подобных системах в отличие от других ОС ядро минимизировано и не выполняет ни одной функции, служащей непосредственно пользователю. Для этой цели применяются многочисленные утилиты, выступающие в качестве посредников между пользователем и ядром. Только в комплекте с ними ядро образует полноценную операционную систему.
Ядро обслуживает запросы процессов. Что же такое процесс? Это понятие является базовым в UNIX-подобных системах. Процесс можно представить себе как виртуальную машину, отданную в распоряжение одной задачи. Каждый процесс считает, что он на машине один и может распоряжаться всеми ее ресурсами. На самом же деле процессы надежно изолированы друг от друга, так что крушение одного не может повредить всей системе
|
Каждый процесс выполняется в собственной виртуальной памяти, в которую никакой другой процесс вмешаться не может. Этим и обеспечивается устойчивость всей системы.
Напомним, что такое виртуальная память. Каждому процессу разрешено считать, что его адреса начинаются с нулевого адреса и далее наращиваются. Таким образом, в 32- разрядной ОС процесс может адресовать 4 гигабайта оперативной памяти. Механизм виртуальной памяти позволяет процессу считать, что именно столько ему и выделено, хотя физически объем ОЗУ вашей машины может быть значительно меньше. Недостающую память заменяет жесткий диск путем записи временно не используемых страниц памяти в раздел подкачки (свопинга).
Разделяемость библиотек между процессами обеспечивается тем, что их код и статические данные отображаются на один и тот же участок физической оперативной памяти.
Таблица процессов
С точки зрения ядра процесс представляет собой запись в таблице процессов. Эта запись содержит сведения о состоянии процесса и данные, существующие в течение всего времени его жизни. Размер таблицы процессов позволяет запускать несколько сотен процессов одновременно. Другая важная информация о процессе — например, таблица всех открытых процессом файлов — хранится в его адресном пространстве. Запись в таблице процессов и пространство процесса вместе составляют контекст, или окружение, процесса. В него входят:
♦ PID — идентификатор процесса. Он принудительно назначается планировщиком при запуске процесса.
|
♦ PPID — идентификатор родительского процесса.
♦ TTY — имя управляющего терминала - терминала, с которого запущен процесс.
♦ WD — текущий каталог процесса, от которого отсчитываются относительные пути.
♦ RID, RGID — реальные ID и групповой ID пользователя, запустившего процесс.
♦ EUID, EGID — эффективные ID и GID.
♦ NICE — показатель уступчивости. Процессы выполняются в режиме разделения времени, то есть время центрального процессора делится между готовыми к выполнению процессами с учетом их приоритета. Чем выше показатель уступчивости, тем ниже приоритет.
♦ Переменные окружения.
Системные вызовы fork() и ехес() или как размножаются процессы
Каждый процесс порождается другим процессом, использующим для этого системный вызов fork(). Таким образом, структура процессов, подобно файловой системе, древовидна. Корнем этого дерева служит init — процесс инициализации системы (см. рис. 2). Он запускается ядром первым, получает идентификатор 1 и порождает еще несколько процессов (сколько и каких, можно узнать из его конфигурационного файла
/etc/inittab), которые, в свою очередь, при участии пользователя порождают другие процессы.
В результате системного вызова fork() родительский процесс полностью копирует рождения дочерний процесс отличается только своим ID. Потом дочерний процесс с помощью вызова ехec() загружает в свое адресное пространство какой-нибудь исполняемый файл и начинает исполнять содержащуюся в нем программу.
Каждый процесс, завершившись, возвращает родительскому процессу какое-то значение, называемое кодом завершения или кодом возврата. По соглашению разработчиков, нулевой код возврата означает успешное завершение, а ненулевые — разнообразные ошибки. Процесс-родитель может приостановить свое выполнение до завершения потомка и выполнить разные действия в зависимости от возвращенного дочерним процессом значения, а может и не делать этого.
|
Иерархия процессов.
Категории процессов
Процессы делятся на три категории:
♦ Системные. Они порождаются ядром особым образом в процессе загрузки и выполняют системные функции (например, планирование процессов или смену страниц виртуальной памяти). Выполняемая ими программа берется не из исполняемого файла, а является частью ядра.
· Пользовательские. Как правило, они порождаются во время сеанса работы пользователя и связаны с терминалом. Если пользовательский процесс работает в интерактивном режиме, то он захватывает терминал в монопольное владение и, пока он не завершится, пользователь не имеет доступа к командной строке на этом терминале. Пользовательские процессы могут работать также в фоновом режиме, освободив командную строку.
· Демоны ( daemon, сокращение от Disk And Execution MONitor ). Запускаются после инициализации ядра. Выполняются в фоновом режиме, не связаны ни с одним пользователем, обеспечивают работу различных служб (например, управление сетью). Главным демоном считается init — процесс инициализации системы.
Сценарии в Linux. Активные и фоновые процесс
Исполняемые файлы в Linux бывают двух видов. Первый – это файлы в собственно исполняемом (executable) формате. Как правило, такие файлы – результат компиляции программ, написанных на одном из языков программирования. В Linux используется несколько форматов исполняемых файлов, состоящих из машинных кодов и служебной информации, необходимой операционной системе для запуска программы: согласно этой информации, ядро Linux выделяет для запускаемой программы оперативную память, загружает программу из файла и передает ей управление. Большинство утилит Linux – программы именно такого, "двоичного" формата.
Второй вид исполняемых файлов – сценарии. Сценарий – это текстовый файл, предназначенный для обработки какой-нибудь утилитой. Чаще всего такая утилита – это интерпретатор некоторого языка программирования, а содержимое такого файла – программа на этом языке.
Запустить сценарий на исполнение можно командой
sh имя_сценария
Для того чтобы запустить процесс сценария параллельно, достаточно добавить в конец командной строки символ "&":
sh имя_сценария&
Процесс, запускаемый параллельно, называется фоновым (background). Фоновые процессы не имеют возможности вводить данные с того же терминала, что и породивший их shell (только из файла), зато выводить данные на этот терминал могут (правда, когда на одном и том же терминале вперемежку появляются сообщения от нескольких фоновых процессов, начинается неразбериха). При каждом терминале в каждый момент времени может быть не больше одного активного (foreground) процесса, которому разрешено вводить данные с этого терминала. На время, пока команда работает в активном режиме, породивший ее командный интерпретатор "уходит в фон", и там, в фоне, выполняет свой wait().
Активный процесс, foreground process - процесс, имеющий возможность вводить данные с терминала. В каждый момент у каждого терминала может быть не более одного активного процесса.
Фоновый процесс, background process - процесс, не имеющий возможности вводить данные с терминала. Пользователь может запустить любое, но не превосходящее заранее заданного в системе, число фоновых процессов.
Сигналы в Linux
Механизм сигналов — это средство, позволяющее сообщать процессам о некоторых событиях в системе, а процессу-получателю — должным образом на эти сообщения реагировать. Послать сигнал может сам процесс (например, при попытке деления на ноль), ядро (при сбое оборудования), пользователь или другой процесс (требуя прервать выполнение задачи).
Всего в Linux 63 сигнала, обозначаемых своими номерами или символическими именами. Имена всех сигналов начинаются с SIG, и эту приставку часто опускают: так, сигнал, требующий прекратить выполнение процесса, называется SIGKILL, или KILL, или сигнал 9.
Получив сигнал, процесс может: игнорировать его; вызвать для обработки установленную по умолчанию функцию; вызвать собственный обработчик (перехватить сигнал). Некоторые сигналы (например, KILL) перехватить или игнорировать невозможно.
Пользователь может послать сигнал процессу с идентификатором PID командой
$ kill [-s <сигнал>] <PID>
где <сигнал> — это номер или символическое имя.
Исполняемые файлы в Linux бывают двух видов. Первый – это файлы в собственно исполняемом (executable) формате. Как правило, такие файлы – результат компиляции программ, написанных на одном из языков программирования. В Linux используется несколько форматов исполняемых файлов, состоящих из машинных кодов и служебной информации, необходимой операционной системе для запуска программы: согласно этой информации, ядро Linux выделяет для запускаемой программы оперативную память, загружает программу из файла и передает ей управление. Большинство утилит Linux – программы именно такого, "двоичного" формата.
Второй вид исполняемых файлов – сценарии. Сценарий – это текстовый файл, предназначенный для обработки какой-нибудь утилитой. Чаще всего такая утилита – это интерпретатор некоторого языка программирования, а содержимое такого файла – программа на этом языке.
Запустить сценарий на исполнение можно командой
sh имя_сценария
Для того чтобы запустить процесс сценария параллельно, достаточно добавить в конец командной строки символ "&":
sh имя_сценария&
Процесс, запускаемый параллельно, называется фоновым (background). Фоновые процессы не имеют возможности вводить данные с того же терминала, что и породивший их shell (только из файла), зато выводить данные на этот терминал могут (правда, когда на одном и том же терминале вперемежку появляются сообщения от нескольких фоновых процессов, начинается неразбериха). При каждом терминале в каждый момент времени может быть не больше одного активного (foreground) процесса, которому разрешено вводить данные с этого терминала. На время, пока команда работает в активном режиме, породивший ее командный интерпретатор "уходит в фон", и там, в фоне, выполняет свой wait().
Активный процесс, foreground process - процесс, имеющий возможность вводить данные с терминала. В каждый момент у каждого терминала может быть не более одного активного процесса.
Фоновый процесс, background process - процесс, не имеющий возможности вводить данные с терминала. Пользователь может запустить любое, но не превосходящее заранее заданного в системе, число фоновых процессов.
Сигналы в Linux
Механизм сигналов — это средство, позволяющее сообщать процессам о некоторых событиях в системе, а процессу-получателю — должным образом на эти сообщения реагировать. Послать сигнал может сам процесс (например, при попытке деления на ноль), ядро (при сбое оборудования), пользователь или другой процесс (требуя прервать выполнение задачи).
Всего в Linux 63 сигнала, обозначаемых своими номерами или символическими именами. Имена всех сигналов начинаются с SIG, и эту приставку часто опускают: так, сигнал, требующий прекратить выполнение процесса, называется SIGKILL, или KILL, или сигнал 9.
Получив сигнал, процесс может: игнорировать его; вызвать для обработки установленную по умолчанию функцию; вызвать собственный обработчик (перехватить сигнал). Некоторые сигналы (например, KILL) перехватить или игнорировать невозможно.
Пользователь может послать сигнал процессу с идентификатором PID командой
$ kill [-s <сигнал>] <PID>
где <сигнал> — это номер или символическое имя.
Несколько часто встречающихся сигналов перечислены в таблице 1. Полный список можно получить по команде kill -l (list).
Таблица 1. Сигналы Linux
№ | Имя | Назначение | Реакция процесса-получателя |
HUP | Hangup — отбой | Демоны перечитывают свои конфигурационные файлы | |
INT | Interrupt | Прекратить выполнение (перехватывается) | |
QUIT | Сильнее, чем INT | тоже | |
ILL | Illegal instruction. Программная ошибка | Обработать ошибку. По умолчанию — прекратить выполнение | |
FPE | Floating point exception, вычислительная ошибка (деление на ноль) | Обработать ошибку. По умолчанию — прекратить выполнение | |
KILL | Убить процесс | Немедленно прекратить выполнение. Не перехватывается | |
SEGV | Segmentation violation. Попытка доступа к чужой области памяти | Обработать ошибку. По умолчанию — прекратить выполнение | |
PIPE | Нет процесса, читающего из конвейера | Обработать ошибку | |
TERM | Termination. Завершить процесс | Корректно завершить выполнение. Перехватывается | |
CHLD | Завершился дочерний процесс | Принять возвращенное им значение | |
CONT | Продолжить работу | Продолжить работу приостановленного процесса | |
STOP | Приостановить процесс | Приостановить выполнение |
Сообщение-сигнал не содержит никакой информации, кроме номера сигнала (для удобства вместо номера можно использовать предопределенное системой имя). Для того чтобы передать сигнал, процессу достаточно задействовать системный вызов kill(), а для того чтобы принять сигнал, не нужно ничего. Если процессу необходимо как-то по- особенному реагировать на сигнал, он может зарегистрировать обработчик, а если обработчика нет, за него отреагирует система. Как правило, это приводит к немедленному завершению процесса, получившего сигнал. Обработчик сигнала запускается асинхронно, немедленно после получения сигнала, что бы процесс в это время ни делал.
Два сигнала – 9 (KILL) и 19 (STOP) – всегда обрабатывает система. Первый из них нужен для того, чтобы убить процесс наверняка (отсюда и название).
Сигнал STOP приостанавливает процесс: в таком состоянии процесс не удаляется из таблицы процессов, но и не выполняется до тех пор, пока не получит сигнал 18 (CONT) – после чего продолжит работу.
В Linux сигналы можно передать активному процессу с помощью управляющих символов:
Interrupt - ^C (Ctrl+C) Stop - ^Z"
Terminate - ^D.
Команды для управления процессами в Linux
Моментальный снимок протекающих в системе процессов – команда ps Моментальный снимок протекающих в системе процессов можно посмотреть с помощью команды ps (process status). Без аргументов она покажет список процессов, связанных с текущей консолью (или виртуальным терминалом). Список возможных ключей команды можно, как обычно, получить по команде ps --help.
Вот некоторые полезные из них:
♦ -р < список_PID>: только процессы с указанными ID;
♦ -u < список_USERID >: только процессы, запущенные указанными пользователями;
♦ -е: все процессы в системе;
♦ -f: полная форма вывода;
♦ -Н: вывод иерархии процессов в форме дерева.
Динамика процессов — команда top
Представление о динамике процессов дает команда top. Она выводит список процессов, отсортированный по количеству занятой памяти или использованного процессорного времени, и обновляет его через указанные промежутки времени (по умолчанию через каждые 3 секунды).
Последний процесс, запущенный из оболочки в фоне, можно из этой оболочки сделать
активным при помощи команды fg (" f ore g round" – "передний план").
Команда bg (b ack g round), запускает в фоне последний остановленный процесс.
Командой kill, как уже говорилось, можно передать процессу сигнал. Команда имеет два параметра - номер сигнала и идентификатор процесса, которому передается сигнал:
kill –номер_сигнала PID