Skip to content

Процессы

Процесс - это программа

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

Каждый процесс имеет свой собственный адресное пространство памяти, где хранятся инструкции программы и её данные. Операционная система управляет выполнением процессов, планируя и координируя их работу на доступных ресурсах компьютерной системы.

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

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

PID

У каждого процесса есть PID - это сокращение от "Process ID" (Идентификатор процесса). Это уникальный числовой идентификатор, присвоенный каждому запущенному процессу в операционной системе.

Каждый процесс имеет свой жизненный цикл, который включает следующие состояния:

Creation

Процесс создается операционной системой, когда пользователь запускает программу, с помощью системных вызовов fork() и clone().

Этапы создания нового процесса:

  1. Выделение ресурсов: ОС выделяет необходимые ресурсы для нового процесса. Эти ресурсы включают в себя адресное пространство памяти, в котором будет храниться код и данные процесса, а также другие системные ресурсы, такие как дескрипторы файлов, идентификаторы и т.д.
  2. Загрузка программы: Процессу необходим код программы для выполнения. ОС загружает код программы в выделенное для него адресное пространство памяти.
  3. Инициализация: Новый процесс может выполнять какую-либо инициализацию, необходимую для его работы. Это может включать в себя установку начальных значений переменных, инициализацию структур данных и т.д.
  4. Запуск: После инициализации процесс переводится в состояние готовности, и операционная система может включить его в очередь готовых к выполнению процессов.
  5. Планирование: ОС выбирает, какой из готовых процессов будет выполняться следующим. Этот выбор может быть основан на различных алгоритмах планирования, которые стремятся обеспечить справедливое распределение ресурсов.
  6. Выполнение: Выбранный процесс начинает активное выполнение на процессоре. Он переходит в состояние выполнения и начинает выполнять свой код.

fork()

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

  • Когда процесс вызывает fork(), операционная система создает новый процесс-дубликат, который полностью копирует текущее состояние родительского процесса, включая переменные, файловые дескрипторы, ресурсы и другие атрибуты.
  • Создается копия виртуального адресного пространства родительского процесса. Важно отметить, что это копия виртуального адресного пространства, а не физической памяти. Оба процесса будут использовать одни и те же физические страницы памяти до тех пор, пока они не будут изменены одним из них. Виртуальные адреса в дочернем процессе указывают на те же физические страницы памяти, что и в родительском процессе. Таким образом, в начале оба процесса разделяют одни и те же данные.
  • Операционная система устанавливает разные идентификаторы процесса (PID) для родительского и дочернего процессов.
  • Дальнейшие изменения данных в одном из процессов не затрагивают другой. Это связано с механизмом копирования на запись (Copy-on-Write, COW). Если один из процессов начинает изменять данные, то операционная система создает новые физические страницы для этого процесса, и копия данных создается только тогда, когда это необходимо.
Copy-on-Write, COW

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

Основные идеи Copy-on-write:

  • Создание копии: Когда процесс или поток хочет создать копию данных, вместо того чтобы фактически копировать данные, он просто создает ссылку на исходные данные.
  • Чтение: Пока данные остаются только для чтения, не требуется создавать дополнительные копии. Копирование выполняется только в случае, если данные должны быть изменены.
  • Изменение: Когда происходит попытка изменить данные, система создает фактическую копию данных. После этого изменения применяются только к этой новой копии, и она становится уникальной для процесса или потока, который начал изменять данные.
  • Оптимизация ресурсов: Таким образом, COW позволяет избежать создания множества ненужных копий данных, что помогает сэкономить память и ресурсы процессора при создании копий.
  • Возвращаемое значение fork() отличается для родительского и дочернего процессов. В родительском процессе fork() возвращает идентификатор дочернего процесса (PID), а в дочернем процессе оно возвращает 0.

Таким образом, fork() позволяет создавать новый процесс с общим начальным состоянием с родительским процессом, но с возможностью изменять свои данные независимо.

Существует более сложная и гибкая версия системного вызова для создания нового процесса - clone.

clone()

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

Вот как работает системный вызов clone:

  • Вызывающий процесс (родительский процесс) вызывает функцию clone() и передает ей различные аргументы, которые определяют параметры создаваемого процесса или потока.
  • Параметры clone() определяют, какие ресурсы будут разделяться между родительским и дочерними процессами. Например, параметр CLONE_VM указывает, что дочерний процесс будет использовать общее виртуальное адресное пространство с родительским процессом. Параметры также могут определять разделяемые файловые дескрипторы, сигналы и другие атрибуты.
  • Операционная система создает новый процесс (или поток) в соответствии с переданными параметрами. Дочерний процесс начинает выполнение с той точки, где был вызван clone().
  • В зависимости от переданных параметров, дочерний процесс может разделять с родительским процессом ресурсы, такие как виртуальное адресное пространство, файловые дескрипторы, память и другие атрибуты. Параметры clone() позволяют гибко определять степень разделения между процессами.

Ready

Состояние "ready" (готов) процесса относится к моменту, когда процесс готов к выполнению и ожидает своей очереди на выполнение на центральном процессоре (CPU).

Когда процесс создается или возвращается из состояния "waiting" (ожидание), например, после ввода/вывода, он перемещается в состояние "ready". Это означает, что процесс готов к выполнению, и операционная система может выбрать его для выполнения на CPU, когда его очередь наступит.

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

Когда процесс в состоянии "ready" получает доступ к CPU, он перемещается в состояние "running" (выполнение) и начинает фактически выполняться.

Running

Состояние "running" (выполнение) процесса - это состояние, в котором процесс фактически выполняется на центральном процессоре (CPU). Когда процесс находится в этом состоянии, он активно использует ресурсы CPU для выполнения своего кода и выполняет вычисления.

Когда операционная система выбирает процесс для выполнения, он перемещается из состояния "ready" (готов) в состояние "running". Процесс начинает исполнять свой код, выполняя инструкции центрального процессора.

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

  • Процесс завершает выполнение своей задачи и вызывает системный вызов для завершения.
  • Процесс передает управление другому процессу, например, после завершения своего кванта времени (если используется планировщик с квантами времени).
  • Процесс блокируется для выполнения операций ввода/вывода или ожидания других событий, и операционная система перемещает его в состояние "waiting" (ожидание).

Waiting

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

События или условия, из-за которых процесс может перейти в состояние "waiting", включают следующие:

  • Операции ввода/вывода (I/O): Процесс может перейти в состояние "waiting", когда он ожидает завершения операций ввода/вывода, таких как чтение данных с диска или ожидание ввода пользователя.
  • Синхронизация: Процессы, работающие параллельно, могут быть вынуждены ждать друг друга для координации работы. Например, один процесс может ожидать, пока другой процесс завершит определенную задачу.
  • Семафоры и блокировки: Процессы могут ожидать доступа к общим ресурсам, защищенным семафорами, блокировками или другими механизмами синхронизации.
  • Таймеры и события: Процессы могут ожидать наступления определенного времени, срабатывания таймера или события.
  • Сетевые операции: Процессы, выполняющие сетевые операции, могут перейти в состояние "waiting", пока не будут получены данные из сети или не наступит событие сетевого взаимодействия.

Zombie

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

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

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

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

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

Termination

Состояние "termination" (завершение) процесса происходит в тот момент, когда процесс полностью завершает свою работу и освобождает все занимаемые им ресурсы. В этом состоянии процесс удаляется из системы и больше не будет выполняться.

Когда процесс достигает своей конечной точки, например, выполнив все свои инструкции или вызвав системный вызов завершения, он переходит в состояние "termination". В этот момент происходит следующее:

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

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