Процессы в Linux
Данной теме посвящено много статей, но в Сети
мало сугубо практических статей. О какой именно практике идет речь,
вы узнаете прочитав эту статью. Правда, одной только практикой нам
не обойтись - вдруг вы не читали всю эту серую массу теории, которую
можно найти в Сети.
Немного теории
Термин "процесс" впервые появился при разработке операционной
системы Multix и имеет несколько определений, которые используются в
зависимости от контекста. Процесс - это:
- программа на стадии выполнения
- "объект", которому выделено процессорное время
- асинхронная работа
Для описания состояний процессов используется несколько моделей.
Самая простая модель - это модель трех состояний. Модель состоит из:
- состояния выполнения
- состояния ожидания
- состояния готовности
Выполнение - это активное состояние, во время которого процесс
обладает всеми необходимыми ему ресурсами. В этом состоянии процесс
непосредственно выполняется процессором.
Ожидание - это пассивное состояние, во время которого процесс
заблокирован, он не может быть выполнен, потому что ожидает какое-то
событие, например, ввода данных или освобождения нужного ему
устройства.
Готовность - это тоже пассивное состояние, процесс
тоже заблокирован, но в отличие от состояния ожидания, он
заблокирован не по внутренним причинам (ведь ожидание ввода данных -
это внутренняя, "личная" проблема процесса - он может ведь и не
ожидать ввода данных и свободно выполняться - никто ему не мешает),
а по внешним, независящим от процесса, причинам. Когда процесс может
перейти в состояние готовности? Предположим, что наш процесс
выполнялся до ввода данных. До этого момента он был в состоянии
выполнения, потом перешел в состояние ожидания - ему нужно
подождать, пока мы введем нужную для работы процесса информацию.
Затем процесс хотел уже перейти в состояние выполнения, так как все
необходимые ему данные уже введены, но не тут-то было: так как он не
единственный процесс в системе, пока он был в состоянии ожидания,
его "место под солнцем" занято - процессор выполняет другой процесс.
Тогда нашему процессу ничего не остается как перейти в состояние
готовности: ждать ему нечего, а выполняться он тоже не может.
Из состояния готовности процесс может перейти
только в состояние выполнения. В состоянии выполнения может
находится только один процесс на один процессор. Если у вас
n-процессорная машина, у вас одновременно в состоянии выполнения
могут быть n процессов.
Из состояния выполнения процесс может перейти либо
в состояние ожидания или состояние готовности. Почему процесс может
оказаться в состоянии ожидания, мы уже знаем - ему просто нужны
дополнительные данные или он ожидает освобождения какого-нибудь
ресурса, например, устройства или файла. В состояние готовности
процесс может перейти, если во время его выполнения, квант времени
выполнения "вышел". Другими словами, в операционной системе есть
специальная программа - планировщик, которая следит за тем, чтобы
все процессы выполнялись отведенное им время. Например, у нас есть
три процесса. Один из них находится в состоянии выполнения. Два
других - в состоянии готовности. Планировщик следит за временем
выполнения первого процесса, если "время вышло", планировщик
переводит процесс 1 в состояние готовности, а процесс 2 - в
состояние выполнения. Затем, когда, время отведенное, на выполнение
процесса 2, закончится, процесс 2 перейдет в состояние готовности, а
процесс 3 - в состояние выполнения.
Диаграмма модели трех состояний представлена на рисунке 1.
Рисунок 1.
Модель трех состояний
Более сложная модель - это модель, состоящая из
пяти состояний. В этой модели появилось два дополнительных
состояния: рождение процесса и смерть процесса. Рождение процесса -
это пассивное состояние, когда самого процесса еще нет, но уже
готова структура для появления процесса. Как говорится в афоризме:
"Мало найти хорошее место, надо его еще застолбить", так вот во
время рождения как раз и происходит "застолбление" этого места.
Смерть процесса - самого процесса уже нет, но может случиться, что
его "место", то есть структура, осталась в списке процессов. Такие
процессы называются зобми и о них мы еще поговорим в этой статье.
Диаграмма модели пяти состояний представлена на рисунке 2.
Рисунок 2.
Модель пяти состояний
Над процессами можно производить следующие операции:
- Создание процесса - это переход из состояния рождения в
состояние готовности
- Уничтожение процесса - это переход из состояния выполнения в
состояние смерти
- Восстановление процесса - переход из состояния готовности в
состояние выполнения
-
Изменение приоритета процесса - переход из
выполнения в готовность
-
Блокирование процесса - переход в состояние
ожидания из состояния выполнения
- Пробуждение процесса - переход из состояния ожидания в
состояние готовности
- Запуск процесса (или его выбор) - переход из состояния
готовности в состояние выполнения
Для создания процесса операционной системе нужно:
- Присвоить процессу имя
- Добавить информацию о процессе в список процессов
- Определить приоритет процесса
- Сформировать блок управления процессом
- Предоставить процессу нужные ему ресурсы
Подробнее о списке процессов, приоритете и обо всем
остальном мы еще поговорим, а сейчас нужно сказать пару слов об
иерархии процессов. Процесс не может взяться из ниоткуда: его
обязательно должен запустить какой-то процесс. Процесс, запущенный
другим процессом, называется дочерним (child) процессом или
потомком. Процесс, который запустил процесс называется родительским
(parent), родителем или просто - предком. У каждого процесса есть
два атрибута - PID (Process ID) - идентификатор процесса и PPID
(Parent Process ID) - идентификатор родительского процесса.
Процессы создают иерархию в виде дерева. Самым "главным" предком,
то есть процессом, стоящим на вершине этого дерева, является процесс
init (PID=1).
На мой взгляд, приведенной теории вполне
достаточно, чтобы перейти к практике, а именно - "пощупать" все
состояния процессов. Конечно, мы не рассмотрели системные вызовы
fork(), exec(), exit(), kill() и многие другие, но в Сети
предостаточно информации об этом. Тем более, что про эти вызовы вы
можете прочитать в справочной системе Linux, введя команду man fork.
Правда, там написано на всеми любимом English, так что за переводом
(если он вам нужен) все-таки придется обратиться за помощью к WWW.
Практика
Для наблюдения за процессами мы будем использовать программу top.
15:03:11 up 58 min, 4 users, load average: 0,02, 0,01, 0,00
52 processes: 51 sleeping, 1 running, 0 zombie, 0 stopped
CPU states: 0,8% user, 0,6% system, 0,0% nice, 0,0% iowait, 98,3% idle
Mem: 127560k av, 124696k used, 2864k free, 0k shrd, 660k buff
13460k active, 17580k inactive
Swap: 152576k av, 8952k used, 143624k free 28892k cached
PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND
3097 den 15 0 1128 1128 832 R 2,8 0,8 0:00 top
1 root 8 0 120 84 60 S 0,0 0,0 0:04 init
2 root 12 0 0 0 0 SW 0,0 0,0 0:00 keventd
3 root 19 19 0 0 0 SWN 0,0 0,0 0:00 ksoftirqd_CPU0
...
Полный вывод программы я по понятным причинам
урезал. Рассмотрим по порядку весь вывод программы. В первой строке
программа сообщает текущее время, время работы системы ( 58 min),
количество зарегистрированных (login) пользователей (4 users), общая
средняя загрузка системы (load average).
Примечание. Общей средней загрузкой системы называется
среднее число процессов, находящихся в состоянии выполнения (R) или
в состоянии ожидания (D). Общая средняя загрузка измеряется каждые
1, 5 и 15 минут.
Во второй строке вывода программы top сообщается,
что в списке процессов находятся 52 процесса, из них 51 спит
(состояние готовности или ожидания), 1 выполняется (у меня только 1
процессор), 0 процессов зомби и 0 остановленных процессов.
В третьей-пятой строках приводится информация о
загрузке процессора, использования памяти и файла подкачки. Нас
данная информация не очень интересует, поэтому переходим сразу к
таблице процессов.
В таблице отображается различная информация о
процессе. Нас сейчас интересуют колонки PID (идентификатор
процесса), USER (пользователь, запустивший процесс), STAT (состояние
процесса) и COMMAND (команда, которая была введена для запуска
процесса).
Колонка STAT может содержать следующие значения:
R - процесс выполняется или готов к выполнению (состояние
готовности)
- D - процесс в "беспробудном сне" - ожидает дискового
ввода/вывода
- T - процесс остановлен (stopped) или трассируется отладчиком
- S - процесс в состоянии ожидания (sleeping)
- Z - процесс-зобми
- < - процесс с отрицательным значением nice
- N - процесс с положительным значением nice (о команде nice мы
поговорим позже)
Давайте просмотрим, когда же процесс находится в
каждом состоянии. Создайте файл process - это обыкновенный
bash-сценарий #!/bin/bash
x=1
while [ $x -lt 10 ]
do
x=2
done
Сделайте этот файл исполнимым chmod +x
./process и запустите его ./process. Теперь перейдите
на другую консоль (ALT + Fn) и введите команду ps -a | grep
process. Вы увидите следующий вывод команды ps: 4035 pts/1 00:00:15 process
Данный вывод означает, что нашему процессу присвоен идентификатор
процесса 4035. Теперь введите команду top -p 4035 15:30:15 up 1:25, 6 users, load average: 0,44, 0,19, 0,07
1 processes: 0 sleeping, 1 running, 0 zombie, 0 stopped
CPU states: 2,3% user, 0,6% system, 0,0% nice, 0,0% iowait, 96,8% idle
Mem: 127560k av, 124496k used, 3064k free, 0k shrd, 1208k buff
15200k active, 16400k inactive
Swap: 152576k av, 15676k used, 136900k free 27548k cached
PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND
4035 den 15 0 1320 1320 988 R 99,9 1,0 0:31 process
Обратите внимание на колонку состояния нашего
процесса. Она содержит значение R, которое означает, что в данный
момент выполняется процесс с номером 4035.
Теперь приостановим наш процесс - состояние T. Перейдите на
консоль, на которой запущен ./process и нажмите Ctrl + Z. Вы увидите
сообщение Stopped. PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND
4035 den 9 0 1320 1320 988 T 0,0 1,0 0:51 process
Теперь попробуем "усыпить" наш процесс. Для этого
нужно сначала "убить" его: kill 4035. Затем добавить перед циклом
while в сценарии ./process строку sleep 10m, которая означает, что
процесс будет спать 10 минут. После этого опять запустите команду ps
-a | grep process, чтобы узнать PID процесса, а затем - команду top
-p PID. Вы увидите в колонке состояния букву S, что означает, что
процесс находится в состоянии ожидания или готовности - попросту
говоря "спит".
Мы вплотную подошли к самому интересному - созданию
процесса-зомби. Во многих статьях, посвященных процессам, пишется
"зомби = не жив, не мертв". А что это означает на самом деле? При
завершении процесса должна удаляться его структура из списка
процессов. Иногда процесс уже завершился, но его имя еще не удалено
из списка процессов. В этом случае процесс становится зомби - его
уже нет, но мы его видим в таблице команды top. Такое может
произойти, если процесс-потомок (дочерний процесс) завершился
раньше, чем этого ожидал процесс-родитель. Сейчас мы напишем
программу, порождающую зомби, который будет существовать 8 секунд.
Процесс-родитель будет ожидать завершения процесса-потомка через 10
секунд, а процесс-потомок завершить через 2 секунды. #include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
int main() {
int pid;
int status, died;
pid=fork();
switch(pid) {
case -1: printf("can't fork
");
exit(-1);
case 0 : printf(" I'm the child of PID %d
", getppid());
printf(" My PID is %d
", getpid());
// Ждем 2 секунды и завершаемся, следующую строку я закомментировал
// чтобы зомби "прожил" на 2 секунды больше
// sleep(2);
exit(0);
default: printf("I'm the parent.
");
printf(" My PID is %d
", getpid());
// Ждем завершения дочернего процесса через 10 секунд, а потом убиваем его
sleep(10);
if (pid & 1)
kill(pid,SIGKILL);
died= wait(&status);
}
}
Для компиляции данной программы нам нужен компилятор gcc: gcc -o zombie zombie.c
Для тех, у кого не установлен компилятор, скомпилированная
программа доступна отсюда.
После того, как программа будет откомпилирована, запустите ее:
./zombie. Программа выведет следующую информацию: I'm the parent
My PID is 1147
I'm the child of PID 1147
My PID is 1148
Запомните последний номер и быстро переключайтесь на другую
консоль. Затем введите команду top -p 1148 16:04:22 up 2 min, 3 users, load average: 0,10, 0,10, 0,04
1 processes: 0 sleeping, 0 running, 1 zombie, 0 stopped
CPU states: 4,5% user, 7,6% system, 0,0% nice, 0,0% iowait, 87,8% idle
Mem: 127560k av, 76992k used, 50568k free, 0k shrd, 3872k buff
24280k active, 19328k inactive
Swap: 152576k av, 0k used, 152576k free 39704k cached
PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND
1148 den 17 0 0 0 0 Z 0,0 0,0 0:00 zombie <defunct>
Мы видим, что в списке процессов появился 1 зомби (STAT=Z),
который проживет аж 10 секунд.
Мы уже рассмотрели все возможные состояния
процессов. Осталось только рассмотреть команду для повышения
приоритета процесса - это команда nice. Повысить приоритет команды
может только пользователь root, указав соответствующий коэффициент
понижения. Для увеличения приоритета нужно указать отрицательный
коэффициент, например, nice -5 process
Автор: Колисниченко Денис
Источник: LinuxRSP.ru
|