Использование UNIX: Часть 8. Управление процессами в UNIX

Применение многозадачности в UNIX

На UNIX®-системах каждая системная и пользовательская задача выполняется как процесс. Система постоянно создает новые процессы, выполнение которых завершается, как только задача процесса будет выполнена или произойдет какое-то непредвиденное событие. В этой статье объясняется, как контролировать процессы и с помощью нескольких команд получать детальную информацию о состоянии процессов в системе.

Мартин Стрейчер, главный редактор, Linux Magazine

Мартин Стрейчер (Martin Streicher) -- главный редактор журнала Linux Magazine. Он имеет степень магистра компьютерных наук Университета Пардью (Purdue University) и с 1982 занимается программированием на языках Pascal, C, Perl, Java и (с недавнего времени) Ruby в UNIX-подобных операционных системах.



12.03.2008

Недавно на улице мне попался настоящий человек-оркестр. Меня это немного развеселило, но, несмотря на это, я был впечатлен его способностями. Используя губную гармошку у рта, банджо и литавры на коленях и ножной барабан настоящий соло-симфонический оркестр отлично исполнил классическую "Лестницу в небо" Led Zeppelin и свободную интерпретацию пятой симфонии Бетховена. Из меня не получится такой многостаночник, и самое большое, на что я способен - это трясти головой и хлопать в ладоши в такт.

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

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

Настоящая многозадачность

В UNIX (и большинстве современных операционных систем, как-то Microsoft® Windows®, Mac OS X, FreeBSD и Linux®) каждая задача представляется как процесс. UNIX способен выполнять много задач одновременно, потому что процессы поочередно выполняются на центральном процессоре в течение очень непродолжительного промежутка времени.

Процесс - это нечто вроде контейнера, объединяющего выполняемое приложение, его переменные среды, состояние потоков ввода/вывода приложения и параметры процесса, включающие в себя его приоритет и степень использования ресурсов системы. Рисунок 1 иллюстрирует понятие процесса.

Рисунок 1. Концептуальная модель процесса в UNIX
Концептуальная модель процесса в UNIX

Можно представлять процесс как независимое государство со своими границами, ресурсами и валовым национальным продуктом.

Каждый процесс имеет своего владельца. Задачи, инициализируемые пользователем, например, его shell и командами, обычно принадлежат этому пользователю. Системные процессы могут принадлежать пользователям с особыми правами или системному администратору root. Например, для повышения безопасности Apache HTTP Server обычно принадлежит выделенному пользователю с именем www, который предоставляет Web-серверу только доступ к файлам, которые ему необходимы для работы.

Владелец процесса может меняться. У одного процесса не может быть одновременно двух владельцев.

Наконец, каждый процесс имеет привилегии. Обычно привилегии процесса соответствуют статусу его владельца в ОС. Например, если пользователь не может получить доступ к какому-либо файлу через команду shell, то программы, которые он запустит при помощи этой оболочки, наследуют то же ограничение на доступ к этому файлу. Правило наследования привилегий можно обойти, т.е. процесс может получить большие привилегии, чем его владелец, если запустить процесс командой, в которой помимо всех прочих действий активируется специальный бит setuid или setgid, как показано на примере ls.

Бит setuid можно задать при помощи chmod u+s. Права доступа, заданные при помощи setuid, выглядят так:

$ ls -l /usr/bin/top
-rwsr-xr-x     1 root  wheel     83088 Mar 20  2005 top

Бит setgid может быть задан при помощи chmod g+s:

$ ls -l /usr/bin/top
-r-xr-sr-x   1 root  tty  19388 Mar 20  2005 /usr/bin/wall

Процесс setuid-, например запускаемый процесс top, выполняется с привилегиями пользователя, которому принадлежит. Следовательно, если запустить top, то у пользователя будут привилегии администратора. Соответственно, процесс setgid выполняется с привилегиями группы владельцев файла.

Например, в Mac OS X, утилита wall, укороченное от "write all", сокращение от write all (отправляет сообщение на каждый физический или виртуальный терминал), задана с setgid tty (как показано выше). Когда пользователь зашел в систему и выбрал терминал, с которого будет вводить команды (терминал становится стандартным каналом ввода для shell), то он становится владельцем терминала, а tty становится группой владельцев. Ввиду того что wall выполняется с привилегиями группы tty, он может открывать и писать вывод на любой терминал.

Получение информации о процессах

Как и для других системных ресурсов, UNIX-система имеет достаточно большой пул процессов. Каждая новая задача, например, запуск vi или xclock, немедленно получает процесс из пула. На UNIX-системах можно получить информацию о процессах при помощи команды ps.

Например, если пользователю нужно вывести список процессов, которыми он владеет, то нужно ввести ps -w --user username:

$ ps -w --user mstreicher

Полностью список процессов можно увидеть при помощи команды ps -a -w -x. Флаги для команды ps отличаются в зависимости от версии UNIX. Для подробной информации по этой команде изучите документацию к своей системе. Флаг -a выбирает все процессы, выполняющиеся на терминале tty. Флаг -x выводит все процессы, не ассоциированные с tty, которые, обычно являются всевозможными системными службами, например, сервер Apache HTTP, утилита-планировщик cron и прочее. Флаг -w предоставляет расширенный набор информации, в который входит, в частности, полный путь к приложению, ассоциированному с каждым процессом.

Утилита ps имеет множество опций, а некоторые версии ps позволяют настраивать отображение результатов работы команды. Например, ниже представлен специальным образом настроенный список процессов:

$ ps --user mstreicher -o pid,uname,command,state,stime,time
  PID USER     COMMAND          S STIME     TIME
14138 mstreic  sshd: mstreicher S 09:57 00:00:00
14139 mstreic  -bash            S 09:57 00:00:00
14937 mstreic  ps --user mstrei R 10:23 00:00:00

Флаг -o настраивает отображение результатов работы команды ps согласно названиям столбцов, переданных параметрами на вход. Параметры pid, uname и command соответствуют столбцам process ID, user name и command соответственно. Параметр state показывает состояние процесса, например, ждущий режим (S) или выполняемый процесс (R), про состояния процесса мы еще поговорим позже. Параметр stime показывает, когда процесс стартовал, и time показывает, как много времени процесс использовал центральный процессор.

Создание новых процессов

В UNIX некоторые процессы выполняются с момента загрузки компьютера до его выключения, но большинство процессов имеет короткий жизненный цикл, ограничивающийся началом и окончанием выполнения задачи. Иногда процесс может быть принудительно завершен. Откуда берутся новые процессы?

Каждый новый процесс в UNIX является перевоплощением существующего процесса. Или, по другому, каждый новый процесс - давайте называть его дочерним - является клоном своего процесса-родителя хотя бы на мгновенье, пока дочерний процесс не начнет выполняться самостоятельно. (Если каждый новый процесс является потомком уже существующего процесса, появляется вопрос "Откуда появился первый процесс?" Посмотрите на врезке ниже ответ на этот вопрос.)

Курица или яйцо

Некоторые споры бесконечны: быть или не быть? PC или Mac? Есть и более старый вопрос: что появилось первым, курица или яйцо?

Если каждый новый процесс в UNIX порождается уже существующим и выполняющимся процессом, откуда берется первый процесс? Ответ: ядро ОС UNIX порождает первый процесс по ходу процесса загрузки.

Имя первого процесса - init, он является "предком" всех других системных процессов. Номер процесса init - 1. Определить статус выполнения этого процесса можно при помощи команды ps -l 1:

F S UID PID PPID  C PRI  
4 S   0   1    0  0  68   0 - 
NI ADDR SZ WCHAN  TTY TIME CMD
  373 select ?   0:02 init [2]

UID00

На рисунках 1 - 4 детально описан механизм создания процесса:

  1. На рисунках 2 и 3, процесс A (Process A) соответствует программе, представленной фиолетовым прямоугольником. Он выполняет инструкции, пронумерованные как 10, 11, 12 и так далее. Процесс A имеет свои собственные данные, свою собственную копию программы, набор открытых файлов, и свою собственную коллекцию переменных среды, которые были собраны, как только процесс А начал свое выполнение.
    Рисунок 2. Процесс А
    Схематичное представление Процесса А
  2. В UNIX системный вызов fork() (называется так потому, что является вызовом или запросом к операционной системе) используется для создания нового процесса. Когда процесс A выполнит вызов fork() в 13-й инструкции, система немедленно создаст точный клон процесса A - процесс Z. Процесс Z имеет те же переменные среды, что и A, то же содержимое памяти, то же состояние выполнения программы и те же самые открытые файлы. Состояние процессов A и Z сразу после того, как процесс А породил процесс Z, показано на рисунке 3.
    Рисунок 3. Процесс A клонирует себя
    Дочерний Процесс Z
  3. В самом начале своего существования процесс Z начинает выполняться с того самого места, где прекратил свое выполнение процесс A. После этого процесс Z начинает выполнение инструкции 14. Процесс A продолжает выполнение той же самой инструкции.
  4. Обычно программная логика инструкции 14 проверяет, является ли текущий процесс дочерним или родительским, таким образом, инструкция 14 для каждого из процессов A и Z выяснит, является ли он дочерним или родительским. Системный вызов fork() вернет 0 дочернему процессу и вернет идентификатор процесса (process ID) процесса Z родительскому процессу.
  5. 5. После предыдущего теста процесс A и процесс Z расходятся, и каждый начинает выполнять свою собственную задачу. Итак, системный вызов для создания процесса называется fork(), что в переводе означает "разветвление".

После разветвления процесс A может продолжить выполнять все то же приложение. Однако процесс Z может немедленно приступить к выполнению другого приложения. Последняя операция по изменению процесса программой называется исполнением (execution), но более подходит к ней название перевоплощение. Хотя ID процесса остается тем же, инструкции внутри процесса целиком заменяются на новую программу. Рисунок 4 показывает состояние процесса Z на этом этапе.

Рисунок 4. Процесс Z теперь полностью независим от своего предка, процесса A
Процесс Z теперь полностью независим от своего предка, Процесса A

Более подробно о разветвлении процессов

Процессы можно разветвлять прямо из командной строки. Для начала откроем xterm (мы знаем, что xterm - это наш собственный процесс и в пределах xterm оболочка shell является отдельным процессом, созданным xterm). Далее введем:

ps  -o pid,ppid,uname,command,state,stime,time

Результат этой команды будет примерно таким:

  PID  PPID USER     COMMAND          S STIME     TIME
16351 16350 mstreic  -bash            S 11:23 00:00:00
16364 16351 mstreic  ps -o pid,ppid,u R 11:24 00:00:00

Согласно полю PPID в этом списке, команда ps является дочерней командой оболочки bash. (Дефис в -bash означает, что данная оболочка является оболочкой входа в систему.) Для выполнения команды psbash путем разветвления создает новый процесс; новый процесс изменяет себя, превращаясь в новый экземпляр команды ps.

Ниже представлен другой пример. Введем:

		sleep 10 & sleep 10 & sleep 10 & ps  -o pid,ppid,uname,command,state,stime,time

Результат работы этой команды должен быть примерно таким:

$ sleep 10 & sleep 10 & sleep 10 & ps  -o pid,ppid,uname,command,state,stime,time
  PID  PPID USER     COMMAND          S STIME     TIME
16351 16350 mstreic  -bash            S 11:23 00:00:00
16843 16351 mstreic  sleep 10         S 11:42 00:00:00
16844 16351 mstreic  sleep 10         S 11:42 00:00:00
16845 16351 mstreic  sleep 10         S 11:42 00:00:00
16846 16351 mstreic  ps -o pid,ppid,u R 11:42 00:00:00

Командная строка создает четыре новых процесса. Вставьте знак амперсанд (&) после каждой команды sleep, тогда эти команды будут работать в фоновом режиме (параллельно с оболочкой). Команда ps - это другой порожденный процесс, но он является высокоприоритетным, что не позволяет оболочке запустить другой процесс до тех пор, пока ps не закончит свое выполнение. Повторюсь, что все четыре процесса порождены оболочкой, о чем говорят значения в столбце PPID. Три процесса sleep имеют метку S и не потребляют ресурсов, пока находятся в спящем режиме.

Для удобства оболочка следит за всеми фоновыми процессами, которые порождает. Список задач можно вывести командой jobs:

$ sleep 10 & sleep 10 & sleep 10 &
[1] 16843
[2] 16844
[3] 16845

$ jobs
[1]   Running                 sleep 10 &
[2]   Running                 sleep 10 &
[3]   Running                 sleep 10 &

Отобразились три процесса, пронумерованные 1, 2, и 3 для удобства. Числа 16843, 16844, и 16845 являются числовыми идентификаторами каждого процесса. Таким образом, идентификатор фонового процесса 1 является 16843.

Можно управлять фоновыми процессами из командной строки, используя их числовые псевдонимы. Например, для завершения команды введем kill %N, где N является числовым псевдонимом процесса (его меткой). Чтобы повысить приоритет команды, которая работает в фоновом режиме, нужно ввести fg %N:

$ sleep 10 & sleep 10 & sleep 10 &
[7] 17741
[8] 17742
[9] 17743

$ kill %7
$ jobs
[7]   Terminated              sleep 10
[8]-  Running                 sleep 10 &
[9]+  Running                 sleep 10 &

$ fg %8
sleep 10

Одновременный асинхронный запуск команд из командной строки является эффективным способом контролировать процессы. Задачи, которые работают долго, например, сложные вычисления или компиляцию большого объема кода, лучше всего делать фоновыми. Для получения результата работы фоновой команды надо перенаправить ее вывод в файл при помощи операторов переадресации >, >&, >> и >>&. Как только фоновая команда закончит свою работу, оболочка выведет результаты ее работы, а потом уже предоставит возможность ввода новой команды:

$ whoami
mstreicher
[8]-  Done                    sleep 10
[9]+  Done                    sleep 10
$

Еще немного об управлении процессами

Некоторые процессы работают с момента включения компьютера до его выключения (init, к примеру), а некоторые процессы перевоплощают себя в новую форму (оболочка, к примеру). Но большинство процессов заканчивают свое выполнение, как только выполнят соответствующую им задачу.

Кроме того, можно временно приостановить деятельность процесса или принудительно завершить процесс командой kill.

Если процесс высокоприоритетный и выполняется, так сказать, на переднем плане, можно приостановить его нажав Control-Z:

$ sleep 10
(Press Control-Z)
[1]+  Stopped                 sleep 10

$ ps
  PID  PPID USER     COMMAND          S STIME     TIME
18195 16351 mstreic  sleep 10         T 12:44 00:00:00

Оболочка приостанавливает процесс и для удобства присваивает ему метку. Эту метку можно использовать для завершения процесса или возобновления его деятельности в высокоприоритетном режиме. Для выполнения процесса в фоновом режиме используется команду bg:

bg %1
[1]+ sleep 10 &

Если процесс высокоприоритетный, но необходимо его завершить, то надо нажать Control-C:

$ sleep 10
(Press Control-C
$ jobs
$

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

UNIX содержит большое количество сигналов, большинство из которых имеет специальное назначение. К примеру, если послать сигнал SIGSTOP процессу, то процесс приостановится. (Для получения полного списка сигналов нужно ввести man 7 signal или kill -L). В следующем примере посылается сигнал с командой kill:

$ sleep 20 &
[1] 19988

$ kill -SIGSTOP 19988

$ jobs
[1]+  Stopped                 sleep 20

Сначала команда sleep запустилась в фоновом режиме с идентификатором процесса 19988. После отправки сигнала SIGSTOP процесс изменил свое состояние, приостановив свое выполнение. Получение другого сигнала SIGCONT вновь запустит процесс, и он продолжит свое выполнение с того места, на котором остановился.

Другими словами оболочка посылает сигнал SIGSTOP высокоприоритетному процессу каждый раз при нажатии Control-Z. Команда bg отправляет сигнал SIGCONT. И Control-C посылает сигнал SIGTERM, который немедленно завершает процесс.

Некоторые сигналы могут блокироваться процессами, и приложения могут быть разработаны так, чтобы перехватывать определенные сигналы и реагировать на них особым образом. Например, системная служба xinetd, которая по требованию запускает сетевые службы, начинает постоянно просматривать свои файлы конфигурации после получения сигнала SIGHUP. В Linux отправка сигнала процессу init может повлечь изменение состояния выполнения системы, вплоть до ее отключения.

Вопрос: Какая разница между командами kill %1 и kill 1?

Я повторюсь, что процессы могут сами генерировать сигналы для себя. Представьте, что программист создает игру, в которой экран меняется каждые пять секунд. Можно запрограммировать таймер на пять секунд и продолжить перерисовку экрана. Как только таймер закончит свое выполнение, он посылает вашему процессу сигнал SIGALRM.

Итак, ответ на предыдущий вопрос: kill %1 завершает фоновый процесс с меткой 1. Команда kill 1 завершит процесс init, что приведет к отключению системы.

При специальных обстоятельствах система может передавать процессам особые сигналы. В случае каких-либо нарушений памяти может быть сгенерирован сигнал SIGSEGV, который немедленно завершит процесс, даже не выгрузив его из ядра. Другой специальный сигнал SIGKILL, который невозможно блокировать или перехватить, немедленно завершает выполнение выбранного процесса.

Как и другим ресурсам UNIX, пользователь может посылать сигналы только тем процессам, которыми он владеет. Это необходимо для того, чтобы не завершить случайно важный системный процесс или процесс других пользователей. Администратор может посылать сигналы любым процессам.

Заключение

UNIX - это сложная система. Она содержит системные службы, устройства, диспетчеры памяти и прочее. К счастью, большая часть этих сложных вещей спрятана от конечного пользователя или, на худой конец, имеет удобные интерфейсы, например, оболочки shell и утилиты с графическим интерфейсом. Кроме того, есть и специальные инструменты, такие как top, ps и kill.

Ресурсы

Научиться

Получить продукты и технологии

  • IBM trial software: ознакомительные версии программного обеспечения для разработчиков, которые можно загрузить прямо со страницы сообщества developerWorks.(EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=AIX и UNIX
ArticleID=294436
ArticleTitle=Использование UNIX: Часть 8. Управление процессами в UNIX
publish-date=03122008