Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

Назад Содержание Вперед

Введение в POSIX'ивизм

(C) Алексей Федорчук, 2005
Опубликовано на сайте LinuxCenter

Глава 7. Процесс пошел

Над нами солнце встает,
Процесс сам по себе идет...
Тимур Шаов

Содержание

Понятие процесса

Понятие процесса принадлежит к тем сущностям, кажущимся интуитивно ясными, и которым, тем не менее, нелегко дать строгое (и при этом удобопонятное) определение. Наиболее распространенное их них - это представление процесса как программы в стадии ее выполнения (Андрей Робачевский. Операционная система Unix. СПб: БХВ-Петербург, 2000).

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

Все сказанное может показаться настолько кучерявым, что вызывает естественный вопрос: а за каким зеленым обычному (=конечному) пользователю-POSIX'ивисту вообще нужно знать о каких-то там процессах? Ведь пользователь MacOS (BSD-системы в своей основе - то есть тоже имеющей понятие процесса) спокойно обходится без этих знаний. Да и в Windows процессы, скорее всего, протекают, однако побуждений знакомиться с ними у пользователя нет ни малейшего.

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

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

Разновидности процессов

Итак, повторюсь: процесс - это все, что происходит в системе. А все происходящее в системе - либо порождено ее ядром (то есть как бы самой системой), либо - одним из ее пользователей. Соответственно этому, процессы бывают системные и пользовательские. На первых мы здесь задерживаться не будем. Скажу только, что запуск системных процессов осуществляется ядром ОС (не важно, какой - Linux там, или FreeBSD), и их задача - управление ресурсами машины (доступом к процессору, памяти, своппингом и т.д.). Важно только помнить, что с системными процессами не коррелируют никакие программы в обычном понимании этого слова (кроме ядра, конечно, которое само по себе - программа; но порождает она далеко не один процесс). То есть: в системе не существует отдельного исполняемого файла, ответственного за запуск программы, исполняемой системным процессом (внятно выразился?) - все они запускаются ядром, которое тоже являет собой просто исполняемый файл, хотя и не совсем обычный по своим функциям.

Из сказанного выше существует единственное исключение, и это - процесс init, прародитель всех прочих процессов, почему его и относят к системным процессам. Хотя он и имеет ассоциированный с ним исполнимый файл (имя его всегда и везде в POSIX-системах - /sbin/init, хотя реально это могут быть разные программы), который вызывается по окончании загрузки системы и порождает все остальные пользовательские процессы. В том числе - процессы getty, открывающие терминал (за этот процесс в разных системах могут отвечать разные программы), и login, ответственный за авторизацию пользователя на этом терминале - ту самую программу, которая, как мы видели в прошлой главе, предлагает ввести пользователю свое имя и пароль.

Процессы getty и login относятся уже к пользовательским процессам. Которые, в отличие от системных, всегда ассоциированы с неким исполняемым файлом. Для процесса getty это будет, например, /usr/libexec/getty, а для процесса login - нечто вроде /usr/bin/login.

Процессы типа getty и login относятся к категории неинтерактивных, то есть тех, которые не привязаны к какому-либо терминалу, и на которые пользователь не может влиять непосредственно (общение с ними возможно только посредством т.н. сигналов, о которых будет говориться несколько позже). Неинтерактивные процессы именуются иногда демонами (daemon). Термин этот не несет в себе мистического смысла, представляя простую аббревиатуру (Disk And Execution MONitor). Они инициируются самой системой при ее загрузке обычным образом (запуском соответствующих программ) и функционируют в фоновом режиме, активизируясь при необходимости совершения некоего действия - печати, доставки почты и т.д. Или, как в случае с login - авторизации пользователя.

Есть еще и процессы интерактивные, отличающиеся тем, что привязаны к некоторому терминалу, через который пользователь может с ними взаимодействовать. Так, авторизовавшись в системе, пользователь (реальный - о виртуальных далее речи не будет) запускает тем самым свой первый процесс - свою "умолчальную" командную оболочку (login shell; в Linux это скорее всего bash, в BSD-системах - /bin/sh или /bin/tcsh). Это - процесс интерактивный, он привязан к определенному терминалу, на котором авторизовался пользователь. И последний может с ним взаимодействовать определенным образом (вводить команды, например).

Атрибуты процесса

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

  • идентификатор процесса (PID);
  • идентификатор родительского процесса (PPID);
  • имя хозяина процесса;
  • идентификатор хозяина процесса (UID);
  • идентификатор группы хозяев (GUID);
  • приоритет;
  • терминал.

Идентификатор процесса - это просто номер его в порядке запуска, от нуля до максимального значения, возможного в данной системе (количество одновременно запущенных процессов - величина конечная). Минимальный (нулевой) номер обычно получает процесс init - первопредок всех остальных процессов в системе: именно так дело обстоит в Linux. Однако в BSD-системах PID, равный нулю, обнаруживается у процесса активизации виртуальной памяти (swapper), а init имеет идентификатор 1.

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

Для рассмотрения смысла остальных атрибутов нам придется обратиться к команде ps, которая и выводит информацию о процесса в виде, доступном пониманию пользователя.

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

Итак, сразу после авторизации пользователя в ответ на команду ps -u будут выведены две строки, состоящие из нескольких колонок, в числе которых - следующие:

USER       PID           COMMAND
alv       5408            -zsh
alv       5598            ps -u

Первая колонка указывает на имя хозяина процесса - как правило (хотя и не обязательно - и позднее можно будет видеть, что это важно), таковым выступает пользователь, этот процесс запустивший. Вторая колонка - идентификатор процесса, третья - имя программы, породившей процесс; очевидно, что в момент сразу после авторизации это будет только командная оболочка - -zsh (символ дефиса перед именем показывает, что это - не просто некая программа, а именно login shell: завершение ее эквивалентно окончанию сеанса работы данного пользователя). Ну и, конечно, сама команда ps - ей ведь тоже соответствует свой процесс, хотя и завершившийся. Так вот, именем хозяина определяются отношения процесса к файлам и иным процессам. То есть процесс получает те же привилегии, которые имеет его хозяин.

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

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

root      5617          passwd

Как могло получиться, что обычный, непривилегированный, пользователь запустил процесс, хозяином которого оказался root? Это станет понятно из дальнейшего. Пока же скажу, для чего это нужно. Ясно, что любой пользователь должен иметь возможность сменить свой пароль. Однако для этого ему придется внести изменения в базу пользовательских акаунтов, а файл /etc/passwd, как мы помним, открыт для изменения только администратору. И потому пользовательский процесс, соответствующий команде passwd, наделяется правами, в обычной жизни этому пользователю недоступными.

Более строго это можно описать так. Как было сказано, система работает не с именем пользователя (по большому счету оно ей до лампочки), а с его идентификатором (UID). Именно он обычно наследуется процессом в качестве идентификатора "хозяина" (и потому называется реальным UID). Однако у процесса есть еще и т.н. эффективный идентификатор "хозяина" (EUID), который собственно определяет привилегии данного процесса. Обычно UID и EUID совпадают - но бывают и исключения из этого правила. Если посмотреть их с помощью команды ps -l для процесса zsh, в поле UID мы увидим цифру 1000 (в данном случае - это UID юзера alv). Однако для процесса passwd поле это будет содержать значение 0, то есть эффективный идентификатор его унаследован не от пользователя, а от root-оператора.

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

Следующий атрибут процесса - его относительный приоритет (NICE), обозначаемый по английски словосочетанием nice value (что интерпретируется обычно как степень "дружелюбия" или "тактичности" по отношению к другим процессам). Он варьирует в диапазоне от -20 (минимальное "дружелюбие", то есть высший приоритет) до +20 (максимальное "дружелюбие", соответствующее низшему приоритету). Прикладные процессы в момент своего рождения получают приоритет 0 (то есть некую "среднюю" степень "дружелюбия").

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

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

Жизнь и смерть процесса

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

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

$ps l

для того, чтобы видеть идентификаторы родительских процессов (за их показ отвечает опция l). Дополнительно отфильтруем (что это такое, будет объясняться в главе 12) процессы, относящиеся только к одной из виртуальных консолей, на которой в данный момент никто не авторизован - для определенности, второй по счету (устройство v1):

$ ps l | grep v1

Для пустой, то есть не несущей пользовательского сеанса, консоли вывод последней команды будет примерно таким (я опускаю столбцы, содержание которых в данный момент для нас не существенно):

UID	PID	PPID	COMMAND	
0	491	1	/usr/libexec/getty

То есть мы имеем в этой консоли единственный процесс getty, принадлежащий суперпользователю (UID 0), имеющий идентификатор 491 и порожденный процессом init (пример приведен для DragonFlyBSD, и потому идентификатор его равен единице).

После же авторизации вывод той же команды приобретет такой вид:

UID	PID	PPID	COMMAND	
0	491	1	login
1001	1949	491	-zsh

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

И еще прошу обратить внимание: PID процесса, ассоциированного с командой login, тот же, что и для процесса, исполнявшего перед этим команду getty, Это свидетельствует, что авторизация пользователя не привела к запуску нового процесса - напротив, замещение одной программы другой произошло в рамках одного и того же процесса (одна из причин, почему не следует отождествлять процесс и программу). А вот идентификатор для zsh - другой: командная оболочка исполняется в порожденном (см. значение PPID) процессе.

Вытеснение одной программы другой в рамках единого процесса - типичный способ запуска новой программы. Так, если из командной строки zsh мы запустим, например, текстовый редактор joe, то в ответ на

$ ps l | grep v1

увидим следующую картину:

UID	PID	PPID	COMMAND	
0	491	1	login
1001	1949	491	-zsh
1001	2208	1949	joe

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

На самом деле родительский процесс перво-наперво порождает свою собственную копию - в данном случае еще один экземпляр командной оболочки zsh (не потому ли первый Shell Борна и получил свое имя, что вызов программы из оболочки напоминает последовательную серию скорлупок?). И различаются в момент зарождения родительский и дочерний процессы фактически только своими PPID (ну и собственными идентификаторами, разумеется). И лишь затем в рамках дочернего процесса осуществляет запуск на исполнение собственно нашей новой программы.

В свою очередь, новый процесс также может выступать в качестве родительского. Так, редактор joe обладает способностью запуска из своей среды программ оболочки. В образовавшемся имитаторе командной строки можно запустить какую-либо другую программу, скажем, поиск файла командой find. Если в процессе поиска посмотреть распределение процессов (например, с другой виртуальной консоли), можно будет увидеть, что процесс joe породил как бы свою копию - но уже с иными идентификаторами (при этом PPID копии, как и следовало ожидать, равен PID оригинала).

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

Управление процессами

Это - одна из причин, почему я в своем пользовательском введении вообще заговорил о процессах. Вторая же причина - то, что необходимость управления процессами время от времени возникает перед пользователем с неотвратимостью рока.

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

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

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

$ kill -15 ### 

где ### - номер (PID) убиваемого процесса, а 15 - численное значение для сигнала TERM (от terminated). Соответственно, команда эта может быть дана и в форме

$ kill -TERM ### 

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

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

$ kill -9 ### 

или

$ kill -KILL ### 

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

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

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

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

Делается это двояко. Если требуется запустить программу с приоритетом, отличным от обычного, используется команда nice с величиной изменения nice value в качестве опции (предваряемой дефисом) и именем программы в качестве опции. Так, команда

$ nice -5 joe

запустит редактор joe с приоритетом, уменьшенным на пять единиц. Если же опустить опцию, приоритет уменьшится на десять единиц. Для увеличения приоритета администратор (и только он) может дать команду

$ nice --7 joe

что приведет к росту приоритета (то есть уменьшению "дружелюбия") на семь единиц.

Кроме того, приоритет может быть изменен для уже запущенных процессов с помощью команды renice, параметром которой является новое значение приоритета, а аргументом идентификатор (PID) процесса. Например, команда

$ renice 7 735

данная от лица пользователя - владельца процесса с PID 735, приведет к установке для него nice value, равного 7 (при условии, что прежний приоритет этого процесса был выше, например, 3 или 0). Администратор же может понизить приоритет того же процесса до значения nice value, равного 2, с помощью команды

$ renice 2 735

или присвоить ему максимальный приоритет:

$ renice -20 735

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

Назад Содержание Вперед

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...