Из этой статьи вы узнаете, что такое процессы, зачем они нужны и как работают в операционных системах Linux.
Что такое процесс
Процесс — это среда выполнения для работы экземпляра программы. Например, есть какая-то программа и при её запуске, для неё создается процесс. Этот процесс наделяется некоторыми свойствами, ему выделяется часть оперативной памяти и присваивается уникальный идентификатор. И программа работает в рамках этого процесса. Дополнительно вы можете прочитать о процессе на wikipedia.
Процессор обрабатывает эти процессы не одновременно. Он очень быстро переключается с одного процесса на другой, за счет чего возникает ощущение многозадачности.
С процессом связан целый ряд атрибутов, которые расширяют или ограничивают его возможности. В течение жизни процесс может находится в разных состояниях.
Жизнь процесса начинается с рождения, совсем как у человека. Еще одно сравнение с человеком, то что процесс может порождать другие процессы. Так процессы в Linux делятся на родительские и дочерние по отношению друг к другу. Например, когда вы работаете в терминале, вы работаете с интерпретатором bash, который работает в своем процессе. И если вы запускаете какую-нибудь команду, например ls, то процесс программы bash запускает процесс для программы ls. При этом bash становится родительским процессом для ls, а ls дочерним для bash.
Единственный процесс, который запускается не другим процессом а ядром, это процесс инициализации системы. Он запускается самым первым и запускает все остальные процессы в Linux. Его атрибут PID равен 1.
Когда процесс завершает свою работу, он сообщает об этом родительскому процессу и освобождает все свои ресурсы, кроме одного атрибута, который называется PID, это уникальный номер процесса. Удалить PID умершего процесса должен его родитель. Пока он этого не сделает умерший процесс остается в состоянии «Зомби». Но об этом позже.
Что помещается в память процесса
Если процесс запущен на 32 разрядной операционной системе, то максимум ему система сможет выделить 2^32 = 4GB памяти. Если же это 64 разрядная операционная система, то теоретически процесс сможет получить 2^48=256TB памяти. В эту оперативную память загружается:
- code — код программы и код всех библиотек нужных программе;
- data — данные, с которыми работает эта программа и библиотеки, и для которых возможно сразу выделить память;
- stack — стек вызовов, когда одна часть программы вызывает другую, а та третью, и все эти вызовы запоминаются здесь;
- heap — куча, когда программе потребовалось выделить определенный объем памяти, который не был заранее известен и выделен.
Если для кода и данных память выделяется стразу в момент рождения процесса, то стек и куча может расти или уменьшаться.
Типы процессов
В системе Linux существуют разные типы процессов:
- пользовательские;
- процессы-демоны;
- процессы ядра.
Пользовательские Linux процессы — работают от имени обычной учетной записи пользователя и выполняются в пространстве пользователя. Если процесс не запущен таким образом, который дает процессу дополнительные разрешения, то пользовательский процесс не имеет доступа к файлам в системе, к которым не имеет доступа сам пользователь запустивший процесс.
Процессы-демоны — предназначенные для работы приложения в фоновом режиме. Такие процессы обычно управляются какими-нибудь службами (сервисами SystemD). Процесс-демон может прослушивать входящие запросы к службе. Например apache2 является процессом-демоном и прослушивает запросы на просмотр веб-страниц. Такие процессы могут работать от имени root, или от имени специальных системных пользователей. Например, apache2 работает от имени пользователя www-data.
Процессы ядра — выполняются только в пространстве ядра. Они похожи на процессы-демоны. Основное отличие состоит в том, что процессы ядра имеют полный доступ к структурам ядра. Процессы ядра не так гибки, как процессы-демоны. Вы можете изменить поведение процесса-демона, изменив конфигурационные файлы и перезагрузив службу, но для изменения процессов ядра может потребоваться перекомпиляция ядра.
Атрибуты процессов
Каждый процесс имеет набор атрибутов, например:
- pid — идентификатор процесса;
- ppid — идентификатор родительского процесса;
- tty — управляющий терминал, с которого поступает ввод и на который поступает вывод. То есть stdin, stderr, stdout;
- sid — идентификатор сеанса;
- ruid — идентификатор пользователя запустившего исполняемый файл;
- rgid — идентификатор группы пользователя запустившего исполняемый файл;
- euid — идентификатор фактического пользователя от имени которого работает процесс;
- egid — идентификатор фактической группы от имени которой работает процесс;
- pgid — идентификатор группы процессов;
- tpgid — идентификатор терминальной группы процессов (forefraund group);
- pri — приоритет работы процесса, чем выше значение, тем выше приоритет. Пользователь, даже root не может менять это значение;
- ni — любезность процесса, от него зависит pri. Чем выше ni, тем ниже pri. Только root может менять это значение;
- s — состояние в котором находится процесс.
Это не весь список атрибутов, на самом деле их больше.
Состояния в которых могут находится процессы Linux
Процесс либо обрабатывается процессором, либо не обрабатывается. Только один процесс может обрабатываться на одном ядре процессора. Все остальные процессы должны ждать или находиться в каком-то другом состоянии. Вот список состояний в которых может находится процесс:
- R (running — запущенный). Процесс находится на обработке у процессора.
- R (runnable — готов к работе). Процесс готов к обработке и находится в очереди к процессору. Running и runnable обозначаются одинаковой буквой R.
- D (uninterruptible sleep — в беспробудном сне). Когда процесс обращается к устройству, например к диску или сетевой карте, он переходит в это состояние. А возвращается из него только после получения запрошенной информации. Обычно в таком состоянии процесс находится не долго. В таком состоянии процесс перестает обрабатывать любые сигналы и, если что-то пойдет не так, то завершить такой зависший процесс, не перезагружая сервер, не получится.
- I (Idle — бездействующий поток ядра). Состояние похоже на D, но такие процессы не нагружают процессор и исключены из расчета средней нагрузки системы (load average).
- S (sleeping — спит). Процесс ожидает какие-то ресурсы, которые в данный момент недоступны. При переходе в это состояние, процесс немедленно отказывается от доступа к процессору. Когда ресурс, который ожидает процесс, становится доступным, процесс может снова перейти в состояние R (runnable). В спящем состоянии процесс продолжает обрабатывать сигналы.
- T (stopped by job control signal — остановленный специальным сигналом). Про сигналы поговорим позже, тут главное понять, что процессы могут обрабатывать сигналы и один из них может остановить процесс. Это состояние похоже на паузу, то есть из этого состояния процесс может выйти и продолжить свою работу в состоянии R или S.
- t (stopped by debugger during trace — остановлен отладчиком во время трассировки). Состояние подобное T, но в этом случае остановка процесса произошла не по сигналу а во время отладки.
- Z (zombie — зомби). Когда процесс завершает свою работу, он освобождает свои ресурсы, но не освобождает свой PID в таблице процессов. Вместо этого он отправляет сигнал родителю, сообщая что он завершается. Родительский процесс должен освободить PID дочернего процесса. Отрезок времени между завершением процесса и когда родитель освободит PID завершенного дочернего процесса называется состоянием зомби. Процесс может остаться в состоянии Zombie, если родительский процесс умрет до того, как освободит PID дочернего процесса.
Итог
Мы познакомились с процессами, узнали какие данные хранятся у них в памяти, какие атрибуты они имеют и в каких состояниях могут находиться.
Дополнительно я рассказал про ограничения 32 разрядной и 64 разрядной операционных систем.
А также, узнали что процессы порождают друг друга, кроме самого первого процесса, который порождается ядром.