Сущность процесса неразрывно связана с мультипрограммированием и многозадачностью операционной системы. Например, в однозадачных операционных системах программы существуют, а процессы — нет.
В однозадачных операционных системах единовременно одна последовательная программа выполняется одним исполнителем (центральным процессором), имея возможность безраздельно использовать все доступные ресурсы (память, устройства ввода-вывода и пр.).
В любой программе можно выделить перемежающиеся блоки инструкций, использующих или центральный процессор (ЦП), или устройства ввода-вывода (УВВ).
При этом, центральный процессор вынужден простаивать при выполнении программой операций ввода-вывода, например, при ожидании окончания записи (или чтения) блока данных на внешний носитель, или при ожидании окончания передачи (или приема) сетевого кадра, или при ожидании событий с устройств человеко-машинного взаимодействия.
С другой стороны, устройства ввода-вывода тоже вынуждены простаивать при выполнении программой вычислительных операций, например, ожидая результата, подлежащего выводу, -или ожидая возникновения у программы потребности в новых исходных данных.
Используя такую модель поведения программ, можно провести анализ потребления ими ресурсов при выполнении. Например, компрессоры gzip, bzip и xz считывают очередной блок данных исходного файла, относительно долго упаковывают его и записывают в результирующий файл, а затем повторяют процедуру до исчерпания блоков исходного файла.
Количество времени, потраченного на вычислительные операции упаковки, будет много больше количества времени, потраченного на чтение исходных данных и запись результатов, поэтому нагрузка на ЦП будет высокой, а на УВВ — нет. Такой же анализ можно привести и для дубликатора dd, копировщика rsync или архиватора tar, которые, наоборот, почти не выполняют никаких вычислений, а сосредоточены на вводе-выводе больших объемов данных, поэтому при их использовании нагрузка на ЦП будет достаточно низкой, а на УВВ — высокой.
Для командного интерпретатора bash, текстовых редакторов nano и vim и других интерактивных программ, взаимодействующих с пользователем, характерны длительные ожидания ввода небольших команд, простая и недолгая их обработка и вывод короткого результата. В результате коэффициент полезного использования и ЦП, и УВВ будет приближен к нулю.
Подобный анализ и желание увеличить коэффициенты полезного использования ресурсов привели к созданию многозадачных операционных систем, основывающихся на простой идее псевдоодновременного выполнения нескольких последовательных программ одним исполнителем.
Для этого вместо простоя в ожидании окончания операции ввода-вывода, начатой некоторой программой, центральный процессор переключается на выполнение другой программы, тем самым увеличивая интегральный коэффициент его полезного использования.
С появлением мультипрограммной смеси (набор программ, между которыми переключается процессор) каждая из ее программ больше не может безраздельно использовать все доступные ресурсы (например, всю память — она одновременно нужна всем программам смеси), в связи с чем операционная система берет на себя задачи диспетчеризации (распределения) ресурсов между ними.
В Linux, как и во многих других операционных системах, программы изолируются друг от друга в специальных «виртуальных» средах, обеспечивающих их процесс выполнения. Каждая такая среда называется процессом и получает долю доступных ресурсов — выделенный участок памяти, выделенные промежутки процессорного времени.
Процесс эмулирует для программы «однозадачный» режим выполнения, словно программа выполняется в одиночку, и «безраздельное» использование ресурсов процесса, как будто это все доступные ресурсы.
Параллельные программы, как указывалось ранее, состоят из независимых ветвей, каждая из которых сама по себе укладывается в модель поведения последовательной программы, поэтому одну параллельную программу можно выполнять в нескольких процессах в псевдоодновременном режиме. Процессы операционной системы, таким образом, являются контейнерами для многозадачного выполнения программ, как последовательных, так и параллельных.
В листинге ниже при помощи команды ps показаны процессы пользователя, упорядоченные в дерево, построенное на основе дочерне-родительских отношений между процессами. Уникальный идентификатор, отличающий процесс от других, выведен в столбце PID (process identifier), а имя и аргументы программы, запущенной в соответствующем процессе, — в столбце COMMAND.
В столбце STAT показано текущее состояние процесса, например S (сон, sleep) или R (выполнение, running, или готовность к выполнению, runnable). Процессы, ожидающие завершения их операций ввода-вывода, находятся в состоянии сна, в противном случае либо выполняются, либо готовы к выполнению, т. е. ожидают, когда текущий выполняющийся процесс заснет, и процессор будет переключен на них.
В столбце TIME показано чистое потребленное процессом процессорное время от момента запуска программы, увеличивающееся только при нахождении им в состоянии выполнения.
Содержимое
Дерево процессов пользователя
fitz@ubuntu:~$ ps fx
PID TTY STAT TIME COMMAND
2156 ? Ssl 0:02 gnome-session —session=ubuntu
2410 ? Ss 0:00 \_/usr/bin/ssh-agent /usr/bin/dbus-launch —exit-with…
2432 ? Si 0:51 \_ /usr/lib/gnome-settings-daemon/gnome-settings-daemon
2451 ? S 1:01 | \ syndaemon -l 2.0 -K -R -t
2442 ? Rl 27:21 \_ compiz
2569 ? Ss 0:00 | \_ /bin/sh -c /usr/bin/compiz-decorator
2570 ? Sl 0:25 | \_ /usr/bin/gtk-window-decorator
7806 ? Ss 0:00 | /bin/sh -c gnome-terminal
7807 ? Si 0:28 | \_ gnome-terminal
7813 ? S 0:00 | \_ gnome-pty-helper
8127 pts/1 Ss 0:00 | \_ bash
10808 pts/1 R+ 0:00 | | \_ ps fx
9321 pts/0 Ss 0:00 | \_ bash
10792 pts/0 S+ 0:00 | | \_ man ps ,
10803 pts/0 S+ 0:00 | | \_ pager -s
10610 pts/2 Ss 0:00 | \_ bash
Управляющий терминал процесса, показанный в столбце TTY, используется для доставки ему интерактивных сигналов при вводе управляющих символов intr ^С, quit ^\ и пр. У части процессов управляющий терминал отсутствует, потому что они выполняют приложения, взаимодействующие о пользователем не посредством терминалов, а через графическую систему.
Процесс по своему определению изолирует свою программу от других выполняющихся программ, что затрудняет использование процессов для выполнения таких параллельных программ, ветви которых не являются полностью независимыми друг от друга и должны обмениваться данными.
Использование предназначенных для этого средств межпроцессного взаимодействия при интенсивном обмене приводит к обременению неоправданными накладными расходами, поэтому для эффективного выполнения таких параллельных программ используются легковесные процессы (LWP, light-weight processes), они же нити (threads). Существует еще один (не очень удачный) перевод понятия thread на русский язык — поток. Во-первых, он конфликтует с переводом понятия stream — поток, а во-вторых, в отличие от stream, thread никуда не течет. А вот процесс (process) содержит в себе нити (thread) абсолютно таким же образом, как и обычная веревка состоит из… нитей.
Механизм нитей позволяет переключать центральный процессор между параллельными ветвями одной программы, размещаемыми в одном (!) процессе.
Нити никак не изолированы друг от друга, и им доступны абсолютно все ресурсы своего процесса, поэтому задача обмена данными между нитями попросту отсутствует, т. к. все данные являются для них общими.
В примере из листинга ниже показаны нити процесса в BSD-формате вывода. Выбор процесса производится по его идентификатору PID, предварительно полученному командой pgrep по имени программы,выполняющейся в искомом процессе.
В выводе наличие нитей процесса отмечает флаг l (Iwp) в столбце состояния STAT, а каждая строчка без идентификатора pid символизирует одну нить. Так как в многонитевой программе переключение процессора производится между нитями, то и состояния сна S, выполнения или ожидания R приписываются отдельным нитям.
Нити процессов, BSD-формат вывода
fttz@ubuntu:~$ pgrep skype
24244
fttz@ubuntu:~$ ps mp 24244
PID TTY STAT TIME COMMAND
24244 ? — 13:14 skype
— — Sl 11:13 —
— — Sl 00:00 —
— — Sl 00:00 —
— — Sl 00:00 —
— — Sl 00:00 —
— — Sl 00:02 —
В листинге ниже показаны нити процесса в SYSV-формате вывода. Выбор процесса производится по имени его программы.
Общий для всех нитей идентификатор их процесса отображается в столбце PID, уникальный идентификатор каждой нити — в столбце LWP (иногда называемый TID, thread identifier), а имя процесса (или собственное имя нити, если задано) — в столбце CMD.
Нити процессов, SYSV-формат вывода
fitz@ubuntu: ~$ ps -LC gnome-terminal
PID LWP TTY TIME CMD
16749 16749 ? 00:00:08 gnome-terminal
16749 16750 ? 00:00:08 dconf worker
16749 16751 ? 00:00:00 gdbus
16749 16758 ? 00:00:00 gmain
Уведомление: Порождение процессов и нитей, запуск программ Linux | Debian GNU/Linux