Перейти к содержанию

13.1 Процессы в Linux (Understanding Linux Processes)

Чтобы эффективно управлять процессами Linux, необходимо сначала разобраться в том, как они функционируют внутри операционной системы. Так что же такое процесс? В нашем контексте процесс (process) — это программа, загруженная с устройства долгосрочного хранения данных (как правило, жёсткого диска) в оперативную память и в данный момент обрабатываемая процессором материнской платы.

В системе Linux запустить процесс могут программы нескольких типов, перечисленных в таблице 13-1.

Тип программы Описание
Двоичные исполняемые файлы (Binary executables) Программы, изначально написанные в виде текстового файла на языке программирования — например, C или C++. Текстовый файл затем проходит через компилятор, который создаёт двоичный файл, пригодный для выполнения процессором.
Встроенные команды оболочки (Internal shell commands) Часть команд, вводимых в командной строке, представляет собой реальные двоичные файлы в файловой системе, которые загружаются и выполняются процессором. Например, когда вы вводите top в командной строке, загружается двоичный файл top. Другие команды, однако, не являются двоичными исполняемыми файлами. Они встроены непосредственно в программу оболочки. Например, команда exit, введённая в командной строке, является именно такой встроенной командой: исполняемого файла с именем «exit» в файловой системе нет — соответствующий программный код хранится внутри самой оболочки.
Сценарии оболочки (Shell scripts) Текстовые файлы, выполняемые посредством оболочки. Внутри сценария можно вызывать двоичные исполняемые файлы. Создание сценариев оболочки рассматривается в одной из следующих глав.

Таблица 13-1. Программы Linux, способные порождать процессы

Многие различные типы программ можно запустить для создания процесса. В системе Linux перечисленные в таблице 13-1 типы программ могут быть загружены в оперативную память и выполнены процессором.

Помните, что операционная система Linux способна выполнять множество процессов «одновременно» на одном процессоре. В зависимости от характера использования системы в конкретный момент времени на ней может работать лишь несколько процессов или же сотни.

В предыдущем абзаце слово «одновременно» взято в кавычки, поскольку большинство процессоров физически не могут выполнять несколько процессов в один и тот же момент. Вместо этого операционная система Linux быстро переключается между различными процессами, создавая иллюзию параллельного выполнения. На самом деле процессор обрабатывает лишь один процесс в каждый момент времени. Все остальные «работающие» процессы в это время ожидают своей очереди в фоновом режиме. Операционная система поддерживает расписание, которое определяет, когда тот или иной процесс получает доступ к процессору. Это называется многозадачностью (multitasking). Поскольку переключение между процессами происходит очень быстро, нам кажется, что процессор выполняет несколько процессов одновременно.

Следует, однако, учитывать два исключения из этого правила. Первое — многоядерные процессоры (multicore CPUs): они действительно способны одновременно выполнять несколько процессов, поскольку каждое ядро представляет собой отдельный процессор. Например, при наличии двух ядер одно может выполнять один процесс, тогда как другое — иной. Второе исключение — процессоры с гиперпоточностью (hyperthreading CPUs), архитектурно позволяющие одному физическому процессору выполнять более одного процесса одновременно.

Типы процессов Linux

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

Например, при запуске офисного пакета LibreOffice (командой libreoffice) из командной строки создаются два пользовательских процесса: oosplash и soffice.bin:

rtracy@openSUSE:~> ps -a
  PID TTY          TIME CMD
27913 pts/0    00:00:00 oosplash
27935 pts/0    00:00:04 soffice.bin
28041 pts/2    00:00:00 ps

Ключевое свойство пользовательских процессов состоит в том, что они запускаются из оболочки и привязаны к соответствующему сеансу оболочки.

Однако не все процессы, выполняемые в системе, являются пользовательскими. Фактически большинство процессов типичной системы Linux относятся к иному типу — системным процессам (system processes), или демонам (daemons). В отличие от пользовательских, системный процесс (как правило) не предоставляет приложения или интерфейса для конечного пользователя. Его назначение — обеспечивать работу системных служб: веб-сервера, FTP-сервера, файлового сервиса (например, Samba), службы печати (например, CUPS) или службы ведения журналов. Такие процессы выполняются в фоновом режиме и обычно не предоставляют никакого пользовательского интерфейса.

Пример системных процессов показан на рис. 13-1.

Примечание

Большинство системных процессов (но не все) имеют в конце имени букву d, обозначающую демон (daemon).

Рис. 13-1. Системные процессы, выполняющиеся в Linux.

Рис. 13-1. Системные процессы

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

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

Первое, что я делаю при запуске новой системы Linux — будь то сервер или рабочая станция, — это отключаю все ненужные демоны. Работа лишних демонов расходует оперативную память и процессорное время. Что ещё серьёзнее, они могут открывать зияющие бреши в безопасности системы. Вы обязаны чётко понимать, какие системные службы запущены на каждой вверенной вам системе Linux. Нужна служба — оставляйте. Не нужна — удаляйте!

Чтобы понять, какие демоны критически важны для функционирования системы, а какие нет, необходимо разобраться в наследовании процессов Linux. Рассмотрим это далее.

Как загружаются процессы Linux (How Linux Processes Are Loaded)

Все процессы Linux запускаются прямо или косвенно одним-единственным процессом — init или systemd (в зависимости от дистрибутива), который запускается ядром Linux при загрузке системы. При этом любой процесс, выполняющийся в системе Linux, может порождать новые процессы. Процесс, запустивший новый процесс, называется родительским (parent process). Вновь созданный процесс называется дочерним (child process).

Это отношение «родитель — потомок» составляет наследование (heredity) процессов Linux. Поскольку любой процесс, включая дочерние, может порождать новые процессы, в системе способны существовать многочисленные поколения процессов. Это показано на рис. 13-2.

Рис. 13-2. Поколения процессов: родительский процесс, дочерние процессы, потомки.

Рис. 13-2. Поколения процессов

На рис. 13-2 первый родительский процесс породил три дочерних процесса. Каждый из этих трёх дочерних процессов, в свою очередь, породил собственных потомков — таким образом, первый родительский процесс стал «дедушкой»! Теперь понятно, почему мы говорим о «наследовании» процессов.

Для любого процесса в системе Linux необходимо однозначно идентифицировать как сам процесс, так и его наследование. При создании процесса ему назначаются два ресурса:

  • Идентификатор процесса (PID) (Process ID) — уникальный числовой идентификатор, присваиваемый каждому процессу в системе.
  • Идентификатор родительского процесса (PPID) (Parent Process ID) — PID родительского процесса (то есть процесса, породившего данный).

Благодаря этим двум числам можно отслеживать наследование любого процесса в системе. Ядро Linux использует таблицу процессов (process table) для учёта всех выполняющихся процессов. Таблица процессов поддерживается операционной системой в памяти и обеспечивает переключение между процессами, их планирование и расстановку приоритетов. Каждая запись таблицы содержит сведения об одном конкретном работающем процессе: имя процесса, его состояние, приоритет и занятые им адреса памяти.

Обратите внимание: на рис. 13-2 изображён «прародительский» процесс, от которого происходят все остальные. Эта схема носит концептуальный характер и призвана проиллюстрировать природу отношений «родитель — потомок» между процессами. Вместе с тем она отражает реальную иерархию поколений в системе Linux. В системе действительно существует «прародительский» процесс, от которого берут начало все остальные, — это процесс init или systemd (в зависимости от дистрибутива).

Примечание

Одни дистрибутивы по-прежнему используют init, тогда как другие (например, Fedora и openSUSE) перешли на systemd. На протяжении последних нескольких лет в сообществе Linux продолжаются споры о том, что предпочтительнее. На момент написания этой книги systemd постепенно вытесняет init по числу внедрений. Для экзамена LPIC-1/Linux+ необходимо знать обе системы.

Ядро автоматически загружает процесс systemd или init в ходе загрузки системы. Процесс systemd или init затем запускает дочерние процессы — например, оболочку входа в систему, — которые, в свою очередь, порождают другие процессы, в частности используемые утилитой vi. Это показано на рис. 13-3.

Рис. 13-3. Процесс systemd как прародитель всех остальных процессов: systemd → оболочка входа → bash → vi.

Рис. 13-3. Процесс systemd как прародитель всех остальных процессов

Тогда как другим процессам операционная система назначает PID случайным образом из таблицы доступных номеров, процесс systemd (или init) всегда получает PID равный 1. Здесь возникает интересный вопрос: если systemd или init — первый процесс, от которого происходят все остальные, каков его PPID? Существует ли он вообще? Да, существует. Поскольку процесс systemd или init запускается непосредственно ядром Linux (которое всегда имеет PID 0), PPID процесса systemd всегда равен 0. Это показано на рис. 13-4.

Рис. 13-4. PPID процесса systemd равен 0, поскольку его запускает ядро с PID 0.

Рис. 13-4. PPID процесса systemd

Процесс systemd (или init) отвечает за запуск всех системных процессов, настроенных на автоматический старт при загрузке. Кроме того, он создаёт оболочку входа, используемую для входа в систему.

Здесь важно обратить внимание на один момент. На рис. 13-3 под оболочкой входа изображена вторая оболочка bash. Может возникнуть вопрос: «Разве нельзя запустить vi прямо из оболочки входа? Зачем нужна вторая оболочка bash

Дело в том, что vi как раз и был запущен из оболочки входа. Почему же тогда между процессом vi и оболочкой входа на схеме показана вторая оболочка? Дело в следующем: каждый раз, когда вы запускаете команду из оболочки (будь то оболочка входа или обычный сеанс), создаётся новый сеанс оболочки — субоболочка (subshell), — внутри которой и выполняется запущенная команда. Субоболочка является самостоятельным процессом со своим PID. PPID субоболочки равен PID оболочки, из которой была введена команда.

Субоболочка остаётся активной до тех пор, пока работает запущенная команда. Процесс команды выполняется внутри субоболочки и получает собственный PID. PPID процесса команды, разумеется, равен PID субоболочки, в которой он работает. Когда процесс команды завершается и завершает работу, субоболочка уничтожается и управление возвращается в исходный сеанс оболочки. Процесс создания новой субоболочки и запуска в ней процесса команды называется ветвлением (forking).

Например, на рис. 13-5 пользователь ввёл команду vi в командной строке оболочки bash. Была создана новая субоболочка, и процесс vi запустился внутри неё. Когда пользователь выходит из vi, субоболочка уничтожается и управление возвращается к исходному экземпляру оболочки.

Рис. 13-5. Запуск процесса из командной строки: bash → субоболочка → процесс vi.

Рис. 13-5. Запуск процесса из командной строки

Теперь, когда вы понимаете, как работают процессы Linux, можно приступать к управлению ими.