Многозадачность, Планирование на основе Приоритетов

Здесь приводятся заметки для Группы Автоматизации DaqGroup
по планированию задач (потоков, процессов) на основе приоритетов,
в первую очередь в рамках библиотеки crwlib и пакета crwdaq.
Смотрите также “ленту новостей” daqgroupnews.md.

Содержание


Планирование задач и система приоритетов - общие сведения

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

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

Итак, современные OS (операционные системы) используют для (псевдо) параллельного выполнения задач, т.е. многозадачности (multitasking) тот или иной алгоритм разделения времени, при котором каждой задаче выделяется часть процессорного времени. Этот алгоритм называют диспетчеризацией или планированием, а соответствующий программный модуль - диспетчером (dispatcher) или планировщиком (scheduler).

Большинство современных планировщиков имеют систему приоритетов, согласно которой планирование выполнения задач (процессов, потоков) выполняется с учетом их приоритетов. Процессорное время выделяется в первую очередь задачам, имеющим более высокий приоритет. При этом высокоприоритетная задача может вытеснить (preempt) низкоприоритетную, если ей необходимо обслуживание. Такое поведение планировщика называется приоритетной вытесняющей многозадачностью (priority based preemptive multitasking).

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

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


Логическая система приоритетов Free Pascal

Операционные системы - такие как Linux, Windows - используют разные алгоритмы диспетчеризации и системы приоритетов, и даже разную терминологию. Свести эти разные системы в одну формулу не получается.

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

Приоритеты процессов (process) и потоков (thread) определяются:

  1. Классом приоритета процесса (ProcessPriority) из набора 6 классов:

  2. Относительным приоритетом потока (ThreadPriority) из набора 7 приоритетов:

Таким образом, есть набор из 6 * 7 = 42 логических приоритетов.
С помощью таблицы приоритетов логические приоритеты на конкретной платформе переводятся в системно - зависимые уровни физических приоритетов, значение и смысл которых определяется для каждой системы по-своему.

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

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


Система приоритетов Windows

С точки зрения ядра Windows, пользовательские задачи (процессы и потоки) имеют абсолютный уровень (level) приоритета в диапазоне [0..31]. Уровни не инвертированы, т.е. чем выше уровень, тем выше приоритет. Уровень 0 соответствует пустому циклу, т.е. специальному (фиктивному) системному потоку, утилизирующему не используемое другими потоками время.

Потоки процессов с классом приоритета RealTime имеют уровень приоритета [16..31],
все остальные пользовательские потоки имеют уровень приоритета в диапазоне [1..15].
Нормальный (по умолчанию) приоритет (Normal, tpNormal) соответствует уровню приоритета 8.

Приоритеты процессов и потоков Windows проецируются на логическую систему приоритетов с помощью следующей таблицы.
Эта таблица определена системой и не меняется. Можно менять только принадлежность потока к той или иной ячейке в таблице, задавая класс приоритета и приоритет потока.

Таблица приоритетов Windows:

Поток/
Процесс
tpIdle tpLowest tpLower tpNormal tpHigher tpHighest tpTimeCritical
Idle 1 2 3 4 5 6 15
Lower 1 4 5 6 7 8 15
Normal 1 6 7 8 9 10 15
Higher 1 8 9 10 11 12 15
High 1 11 12 13 14 15 15
RealTime 16 22 23 24 25 26 31

Переключение потоков идет в циклическом режиме Round Robin по таймеру с квантом времени 10 мс (на одноядерных процессорах) или 16 мс (на многоядерных процессорах). С помощью специальных системных функций системный квант времени можно изменять в диапазоне 1..16 мс.

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

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


Система приоритетов Linux

Планировщик (scheduler) ядра Linux оперирует с потоками, имеющими параметры описания приоритетов (prio, nice, rlimit) и алгоритмы планирования, приведенные ниже.

Алгоритмы планирования.

Алгоритм prio nice rlimit Описание
Алгоритмы разделения времени Используются для большинства обычных прикладных задач.
SCHED_OTHER 100..139 -20..19 1..40 Планировщик по умолчанию CFS (Completely Fair Scheduler).
SCHED_BATCH 100..139 -20..19 1..40 Планировщик пакетной обработки данных (неинтерактивных задач).
SCHED_IDLE 100..139 нет нет Фоновый планировщик с очень низким приоритетом (idle).
Алгоритмы реального времени Используются для важных (критических) прикладных задач.
SCHED_FIFO 1..99 нет нет Планирование по порядку FCFS (first comes, first serve).
SCHED_RR 1..99 нет нет Планирование по циклу RR (round robin).
SCHED_DEADLINE 1..99 нет нет Планирование с предельным сроком обслуживания.

Алгоритмы планирования делятся на две группы:

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

Параметры для описания приоритета.

Параметр Диапазон Формулы Описание
prio 1..139 120+nice, 140-rlimit Инверсный приоритет с точки зрения ядра.
nice -20..19 prio-120, 20-rlimit Инверсный приоритет (уступчивость) для алгоритмов разделения времени.
rlimit 1..40 140-prio, 20-nice Приоритет (в формате команды rlimit) для алгоритмов разделения времени.

Параметр rlimit используется в системных вызовах (и в команде rlimit) по той причине, что параметр nice лежит в диапазоне [-20..19] и включает значение -1, которое используется как признак ошибки в системных вызовах. Это создает неоднозначность интерпретации результатов системных вызовов. Для устранения неоднозначности вместо nice используется легко вычисляемое значение rlimit, которое неотрицательно и заведомо отличается от кода ошибки.

Для задания приоритетов задач (процессов, потоков) в системе Unix в библиотеке crwlib используется параметр nice, задаваемый в соответствии с таблицей:

Таблица приоритетов в системе Unix в терминах Nice:

Поток/
Процесс
tpIdle tpLowest tpLower tpNormal tpHigher tpHighest tpTimeCritical
Idle 19 17 16 15 14 13 -5
Lower 19 12 11 10 9 8 -10
Normal 19 2 1 0 -1 -2 -20
Higher 14 -3 -4 -5 -6 -7 -20
High 9 -8 -9 -10 -11 -12 -20
RealTime 4 -13 -14 -15 -16 -17 -20

Таблица приоритетов в системе Linux в терминах rlimit:

Поток/
Процесс
tpIdle tpLowest tpLower tpNormal tpHigher tpHighest tpTimeCritical
Idle 1 3 4 5 6 7 25
Lower 1 8 9 10 11 12 30
Normal 1 18 19 20 21 22 40
Higher 6 23 24 25 26 27 40
High 11 28 29 30 31 32 40
RealTime 16 33 34 35 36 37 40

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

При задании приоритетов надо иметь в виду, что в системе Unix процессы пользователя могут только уменьшать свой приоритет, т.е. повышать значение nice. Повышать приоритет можно только с правами root, поэтому предполагается, что для пользователя доступен вызов sudo, причем без пароля. Это поведение sudo можно настроить стандартными средствами, через панель управления.

Необходимо также понимать разницу в работе системы приоритетов Windows и Linux.

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

Под Linix параметр nice каждого потока задается независимо. Значение nice для потоков вычисляется в момент его задания по таблице с текущим значением приоритета процесса, т.е. основного потока процесса. Если приоритет процесса изменяется, это означает лишь изменение параметра nice для основного потока процесса. Все остальные потоки свой приоритет не меняют. Это различие в поведении приоритетов потоков надо иметь в виду при решении задач прикладного программирования.

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


Успешной работы, группа автоматизации DaqGroup!

Copyright(c) 2023 Alexey Kuryakin daqgroup@mail.ru