Common Intermediate Language и системное программирование в Microsoft .NET

Основы многозадачности

Разбить на страницы
Показывать лекцию целиком

Многозадачность в Windows

Для современных операционных систем и для различных систем программирования в современном мире поддержка разработки и реализация многозадачности стала необходимой. При этом на применяемые решения влияет значительное число факторов.

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

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

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

Основные понятия

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

  • Мультипроцессирование - использование нескольких процессоров для одновременного выполнения задач.
  • Мультипрограммирование - одновременное выполнение нескольких задач на одном или нескольких процессорах.
  • В завершение знакомства укажем некоторые термины, определяющие базовые понятия, которыми оперируют операционные системы.

    Мультипроцессирование

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

    (рис 6.1) Разные подходы к реализации мультипроцессирования

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

    Кроме того, очень часто используются многопроцессорные вычислительные системы, в которых используется несколько центральных процессоров. Сложилось несколько подходов к созданию таких компьютеров:

  • наиболее массовыми являются так называемые SMP (Shared Memory Processor или Symmetric MultiProcessor) машины. В таких компьютерах несколько процессоров подключены к общей оперативной памяти и имеют к ней равноправный и конкурентный доступ (см. рис 6.2(рис 6.2) SMP компьютер
  • при необходимости создания систем с качественно большим числом процессоров прибегают к MPP (Massively Parallel Processors) системам. Для этого используют несколько однопроцессорных или SMP-систем, объединяемых с помощью некоторого коммуникационного оборудования в единую сеть (см. рис 6.3(рис 6.3) MPP система
  • иногда используют так называемые NUMA и cc-NUMA архитектуры; они являются компромиссом между SMP и MPP системами: оперативная память является общей и разделяемой между всеми процессорами, но при этом память неоднородна по времени доступа. Каждый процессорный узел имеет некоторый объем оперативной памяти, доступ к которой осуществляется максимально быстро; для доступа к памяти другого узла потребуется значительно больше времени (см. рис 6.4(рис 6.4) NUMA или cc-NUMA система
  • Таким образом, с точки зрения реализации мультипроцессирования, для разработчиков ПО важно иметь представление о том, каковы средства взаимодействия между параллельно работающими ветвями кода - общая память с равноправным или неравноправным доступом, либо некоторая коммуникационная среда с механизмом пересылки данных. Наибольшее распространение получили SMP и MPP системы, соответственно, большинство операционных систем содержат необходимые средства для эффективного управления SMP системами. Для реализации MPP систем, как правило, используются обычные операционные системы на всех узлах и либо обычные сетевые технологии, с применением распространенных стеков протоколов, либо специфичное коммуникационное оборудование со своими собственными драйверами и собственными средствами взаимодействия с приложениями. NUMA системы распространены в меньшей степени, хотя выпускаются серийно. Нормальным при этом является применение массовых операционных систем, рассчитанных на SMP установки, несмотря на то, что это несколько снижает эффективность использования NUMA.

    Windows содержит встроенные механизмы, необходимые для работы на SMP; также возможна установка этой ОС на cc-NUMA системах (современные версии Windows имеют механизмы поддержки cc-NUMA систем). Специальных, встроенных в ОС средств для исполнения приложений на MPP системах в Windows не предусмотрено. Windows предполагает альтернативное применение MPP систем, построенных на обычных сетях, для реализации web- или файловых серверов с балансировкой нагрузки по узлам кластера.

    Мультипрограммирование

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

    Важно подчеркнуть, что мультипрограммирование предполагает управление одновременно выполняющимися приложениями пользователя, а не вообще всяким кодом. Любая реальная вычислительная система должна предусматривать специальные меры для своевременного обслуживания поступающих прерываний, исключений и остановок. Такое обслуживание должно выполняться независимо от работы приложений пользователя и в большинстве случаев имеет абсолютный приоритет над приложениями, так как задержка в обработке подобных событий чревата возникновением неустранимых сбоев и потерь данных. В результате операционные системы предоставляют некоторый механизм, обслуживающий возникающие прерывания и только в промежутках между прерываниями - приложения пользователя. Более того, поскольку аппаратные прерывания происходят в большинстве случаев асинхронно по отношению к приложениям и по отношению к другим прерываниям, то получается так, что система должна содержать два планировщика или диспетчера - один для прерываний, другой для приложений. Работа диспетчера прерываний здесь не рассматривается, поскольку относится сугубо к ядру операционной системы и практически не затрагивает работу приложений.

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

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

    (рис 6.5) Планирование задач

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

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

    Выделяют понятия вытесняющей и невытесняющей многозадачности: в случае невытесняющей многозадачности решение о переключении принимает выполняемая в данный момент задача, а в случае вытесняющей многозадачности такое решение принимается операционной системой (или иным арбитром), независимо от работы активной в данный момент задачи.

    На приведенном графе состояний задачи (см. рис. 6.6) прямая линия от состояния "выполнение" к состоянию "готовность" нарисована пунктиром, чтобы выделить отличие невытесняющей многозадачности от вытесняющей. В случае невытесняющей многозадачности выполняющаяся задача может либо завершиться, либо перейти в состояние "ожидание".

    (рис 6.6) Граф состояния задачи

    И тот, и другой переходы определены логикой работы самой задачи. На графе состояний задачи в случае невытесняющей многозадачности пунктирной линии от состояния "выполнение" к состоянию "готовность" не будет. В случае вытесняющей многозадачности вытеснение осуществляется по решению системы, а не только по инициативе задачи.

    Для невытесняющей многозадачности характерно, что операционная система передает задаче управление и далее ожидает от нее сигнала, информирующего о возможности переключения на другую задачу; сама по себе операционная система выполняемую задачу не прерывает. Именно поэтому невытесняющая многозадачность рассматривается как многозадачность с относительными приоритетами - пока задача сама не сообщит, что настал подходящий для переключения момент, система не сможет передать управление никакой другой, даже высокоприоритетной, задаче.

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

    Характерный пример невытесняющей многозадачности - 16-ти разрядные Windows (включая собственно 16-ти разрядные версии Windows, выполнение 16-ти разрядных приложений в Windows-95, 98, ME и выполнение 16-ти разрядных приложений в рамках одной Windows-машины в NT, 2000, XP и 2003). В таких приложениях операционная система не прерывает выполнение текущей задачи до вызова ею функций типа GetMessage или WaitMessage, во время которых Windows осуществляет при необходимости переключение на другую задачу.

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

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

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

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

    (рис 6.7) Моменты перепланирования задач

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

  • запуск задачи (для возможно скорейшего начала исполнения);
  • досрочное освобождение процессора до исчерпания отведенного кванта (велик шанс, что задача и в этот раз так же быстро отдаст управление);
  • частый вызов операций ввода-вывода (при этом задача чаще находится в ожидании завершения операции, нежели занимает процессорное время);
  • продолжительное ожидание в очереди (приоритет ожидающей задачи часто постепенно начинают увеличивать);
  • и многие другие.
  • Работа планировщика существенно усложняется в случае SMP машин, когда необходимо принимать во внимание привязку задач к процессорам (иногда задаче можно назначить конкретный процессор) и то, на каком процессоре задача выполнялась до того (это позволяет эффективнее использовать кэш-память процессора).

    Реализации Windows NT, 2000, XP, 2003+ предусматривают достаточно развитый и сложный планировщик, учитывающий множество факторов и корректирующий как назначение и длительность отводимых задаче квантов, так и приоритеты задач. При этом планировщик является настраиваемым, и его логика работы несколько отличается в зависимости от настроек системы (некоторые доступны через панель управления) и от назначения системы (работа планировщика различна у серверов и рабочих станций).

    Важно отметить, что Windows является гибкой системой разделения времени с вытесняющей многозадачностью и не может рассматриваться в качестве системы реального времени. Даже те процессы, которые с точки зрения Windows относятся к классу процессов так называемого "реального времени", на самом деле требованиям, предъявляемым к системам реального времени, не удовлетворяют. Такие процессы получат приоритетное распределение процессорного времени и будут обрабатываться планировщиком с учетом их "особого статуса"; однако при этом нельзя гарантировать строгого выполнения временных ограничений. Более того, в силу используемых механизмов управления памятью, нельзя точно предсказать время, необходимое для выполнения той или иной операции. В любой момент времени при самом невинном обращении к какой-либо переменной или функции может потребоваться обработка ошибок доступа, подкачка выгруженных страниц, освобождение памяти и т.д. - то есть действия, время завершения которых предсказать крайне трудно. Фактически можно давать лишь вероятностные прогнозы по времени выполнения той или иной операции. До определенных рамок Windows можно применять в мягких системах реального времени - с достаточно свободными ограничениями, но даже незначительная вероятность превышения временных ограничений иногда просто недопустима.

    Базовая терминология

    В операционных системах сложилось несколько подходов к реализации многозадачности, и, соответственно, принятая в разных операционных системах терминология несколько отличается. Так, обычно разделяют понятия задачи, процесса и потока. При этом понятие задачи является в большей степени историческим, либо очень специфичным. Это понятие сформировалось, когда единицей выделения процессорного времени была сама задача; планировщик же мог только переключать задачи. В современных системах большее распространение получил подход, в котором в рамках одной "задачи" может быть выделено несколько одновременно выполняемых ветвей кода, соответственно термин "задача" заместился терминами "процесс" и "поток".

    Процесс является объектом планирования адресного пространства и некоторых ресурсов, выделенных задаче. Но при этом процесс не является потребителем процессорного времени и не подлежит планированию.

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

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

    В Windows для обозначения этих понятий использованы термины process (процесс), thread (поток) и fiber (волокно). Достаточно часто термин "thread" переводится на русский язык как "нить", а не "поток". Термин "fiber" также может переводиться либо как "нить", либо как "волокно". Поток соответствует потоку ядра и планируется ядром операционной системы, а волокно соответствует потоку пользователя и планируется в приложении пользователя.

    В операционной системе для описания потоков используются объекты двух типов - так называемые дескрипторы и контекст. Дескрипторы содержат информацию, описывающую поток, но не его текущее состояние исполнения. Контекст потока содержит информацию, описывающую непосредственно состояние исполнения потока. Так, например, дескриптор должен содержать переменные окружения, права доступа, назначенные потоку, приоритет, величину кванта и так далее, тогда как контекст должен сохранять информацию о состоянии стека, регистров процессора и т.д. Дескрипторы содержат актуальную в каждый момент информацию, а контекст обновляется в тот момент, когда поток выходит из исполняемого состояния. Из контекста восстанавливается состояние потока при возобновлении исполнения. Пока поток выполняется, содержимое контекста не является актуальным и не соответствует его реальному состоянию.

    Реализация в Windows

    В современных полновесных реализациях Windows (Windows 2000, Windows XP, Windows 2003) планировщик ядра выделяет процессорное время потокам. Управление волокнами возложено на приложения пользователя: Windows предоставляет набор функций, с помощью которых приложение может управлять созданными волокнами. Фактически для волокон реализуется невытесняющая многозадачность средствами приложения; с точки зрения операционной системы, все волокна должны быть созданы в рамках потоков (один поток может быть "расщеплен" на множество волокон средствами приложения) и система никак не вмешивается в их планирование.

    В Windows определен список событий, которые приводят к перепланированию потоков:

  • создание и завершение потока;
  • выделенный потоку квант исчерпан;
  • поток вышел из состояния ожидания;
  • поток перешел в состояние ожидания;
  • изменен приоритет потока;
  • изменена привязка к процессору.
  • В целях уменьшения затрат на планирование потоков несколько изменен граф состояний потока. На рис. 6.6 приведен "классический" вид графа состояний задачи, а на рис. 6.8 - граф состояний потока в Windows. Переход из состояния "готовность" в состояние "выполнение" сделан в два этапа - выбранный к выполнению поток подготавливается к выполнению и переводится в состояние "выбран"; эта подготовка может осуществляться до наступления момента перепланирования, и в нужный момент достаточно просто переключить контекст выполняющегося потока на выбранный.

    (рис 6.8) Граф состояний потока

    Также в два этапа может происходить переход из состояния "ожидание" в "готовность": если ожидание было долгим, то стек потока может быть выгружен из оперативной памяти. В этом случае поток переводится в промежуточное состояние до завершения загрузки стека - в списке готовых к выполнению потоков находятся только те, которые можно начать выполнять без лишнего ожидания.

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

    Процесс выбора потока для выполнения усложняется в случае SMP систем, когда помимо приоритета готового к исполнению потока учитывается, на каком процессоре ранее выполнялся код данного потока.

    В Windows выделяют понятие "идеального" процессора - им назначается процессор, на котором запускается приложение в первый раз. В дальнейшем система старается выполнять код потока именно на этом процессоре - для SMP систем это решение улучшает использование кэш-памяти, а для NUMA систем позволяет, по большей части, ограничиться использованием оперативной памяти, локальной для данного процессора. Заметим, что диспетчер памяти Windows при выделении памяти для запускаемого процесса старается учитывать доступность памяти для назначенного процессора в случае NUMA системы.

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

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

    Управление квантованием

    Квантование потоков осуществляется по тикам системного таймера, продолжительность одного тика составляет обычно 10 или 15 мс, больший по продолжительности тик назначают многопроцессорным машинам. Каждый тик системного таймера соответствует 3 условным единицам; величина кванта может варьироваться от 2 до 12 тиков (от 6 до 36 единиц).

    Параметр реестра HKLM\SYSTEM\CurrentControlSet\Control\PriorityControl\ Win32PrioritySeparation предназначен для управления квантованием. На рис. 6.9 дан формат этого параметра для Windows 2000-2003, а в таблице 6.1 приводятся длительности квантов в условных единицах для разных значений полей параметра Win32PrioritySeparation.

    (рис 6.9) Управление квантованием в Windows (длительность кванта показана в табл. 6.1)
    Длительность кванта
    Короткий квант Длинный квант
    Значение младших 2-х бит параметра Win32PrioritySeparation 01 2 01 2
    Переменная длительность 612 18 1224 36
    Фиксированная длительность 1818 18 3636 36

    Этот параметр может быть изменен с помощью панели управления, однако, лишь в очень ограниченных рамках:

    "System Properties|Advanced|Performance:Settings|Advanced|Adjust for best performance of:" позволяет выбрать только:

  • "applications"

    Короткие кванты переменной длины, значение 0x26 т.е. 10 01 10 (короткие кванты переменной длительности, 18 ед.).

  • "background services"

    Длинные кванты фиксированной длины, значение 0x18 т.е. 01 10 00 (длинные кванты фиксированной длительности, 36 ед.). Более тонкая настройка возможна с помощью редактора реестра.

  • Управление длительностью кванта связано с активностью процесса, которая определяется наличием интерфейса пользователя (GUI или консоль) и его активностью. Если процесс находится в фоновом режиме, то длительность назначенного ему кванта соответствует "нулевым" колонкам таблицы 6.1 (выделены серым цветом; т.е. длительности 6 или 12 - для переменной длины кванта или 18 и 36 - для фиксированной). Когда процесс становится активным, то ему назначается продолжительность квантов, исходя из значения двух младших бит параметра Win32PrioritySeparation в соответствии с приведенной таблицей.

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

    Управление приоритетами

    В Windows выделяется 32 уровня приоритетов. 0 соответствует самому низкому приоритету (с таким приоритетом работает только специальный поток обнуления страниц), 31 - самому высокому. Этот диапазон делится на три части:

  • Приоритет 0 - соответствует приоритету потока обнуления страниц.
  • Приоритеты с 1 по 15 - соответствуют динамическим уровням приоритетов. Большинство потоков работают именно в этом диапазоне приоритетов, и Windows может корректировать в некоторых случаях приоритеты потоков из этого диапазона.
  • Приоритеты с 16 по 31 - соответствуют приоритетам "реального времени". Этот уровень достаточно высок для того, чтобы поток, работающий с таким приоритетом, мог реально помешать нормальной работе других потоков в системе - например, помешать обрабатывать сообщения от клавиатуры и мыши. Windows самостоятельно не корректирует приоритеты этого диапазона.
  • Для некоторого упрощения управления приоритетами в Windows выделяют "классы приоритета" (priority class), которые задают базовый уровень приоритета, и "относительные приоритеты" потоков, которые корректируют указанный базовый уровень. Операционная система предоставляет набор функций для управления классами и относительными приоритетами потоков.

    Планировщик операционной системы также может корректировать уровень приоритета (из диапазона 1-15), однако базовый уровень (т.е. класс) не может быть изменен. Такая коррекция приоритета выполняется в случае:

  • Завершения операции ввода-вывода - в зависимости от устройства, приоритет повышается на 1 - 8 уровней.
  • По окончании ожидания события или семафора (см. далее) - на один уровень.
  • При пробуждении GUI потоков - на 2 уровня.
  • По окончании ожидания потоком активного процесса (определяется по активности интерфейса) - на величину, указанную младшими 2 битами параметра Win32PrioritySeparation (см. управление длительностью кванта).
  • В случае коррекции приоритета по одной из перечисленных причин, повышенный приоритет начинает постепенно снижаться до начального уровня потока - с каждым тиком таймера на один уровень.

    Еще один случай повышения приоритета (вместе с увеличением длительности кванта) - процесс долгое время не получал процессорного времени. В этой ситуации система раз в 3-4 секунды назначает процессу приоритет, равный 15, и квант удвоенной длительности. По истечении этого кванта приоритет возвращается к прежнему значению и восстанавливается рекомендуемая длительность кванта.

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

    Соответствие классов приоритета и относительных приоритетов потоков уровням
    Уровень Класс приоритета (задает базовый уровень приоритета)
    REALTIME 24 HIGH 13 ABOVE_NORMAL 10 NORMAL BELOW_NORMAL 6 IDLE 4
    Foreground 9 Normal 8 Background 7
    31 TIME_CRITICAL

    Уровни приоритета с 16 по 31 отведены только для класса REALTIME_PRIORITY_CLASS

    Не рекомендуется создавать потоки с таким классом приоритета, так как это может повлиять на обработку сообщений от клавиатуры, мыши, сохранение на диске данных кэша и т.д.
    30 6
    29 5
    28 4
    27 3
    26 HIGHEST
    25 ABOVE_NORMAL
    24 NORMAL (24)
    23 BELOW_NOR-MAL
    22 LOWEST
    21 -3
    20 -4
    19 -5
    18 -6
    17 -7
    16 IDLE
    15 TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL
    14 ABOVE_NOR-MAL
    13 NORMAL (13)
    12 BELOW_NOR-MAL HIGHEST
    11 LOWEST ABOVE_NOR-MAL HIGHEST
    10 NORMAL (10) ABOVE_NOR-MAL HIGHEST
    9 BELOW_NOR-MAL NORMAL (9) ABOVE_NOR-MAL HIGHEST
    8 LOWEST BELOW_NOR-MAL NORMAL (8) ABOVE_NOR-MAL HIGHEST
    7 LOWEST BELOW_NOR-MAL NORMAL (7) ABOVE_NOR-MAL
    6 LOWEST BELOW_NOR-MAL NORMAL (6) HIGHEST
    5 LOWEST BELOW_NOR-MAL ABOVE_NOR-MAL
    4 LOWEST NORMAL (4)
    3 BELOW_NOR-MAL
    2 LOWEST
    1 IDLE IDLE IDLE IDLE IDLE IDLE IDLE
    0 приоритет потока обнуления страниц

    В зависимости от настройки планировщика, NORMAL_PRIORITY_CLASS с базовым уровнем приоритета 8 может быть "расщеплен" на два базовых уровня - для потоков активных процессов (базовый уровень 9) и для потоков фоновых процессов (базовый уровень 7). Для класса HIGH_PRIORITY_CLASS относительные приоритеты потока THREAD_PRIORITY_HIGHEST и THREAD_PRIORITY_TIME_CRITICAL дают одинаковое значение приоритета 15.

    Страницы:

    Многозадачность в Windows

    Для современных операционных систем и для различных систем программирования в современном мире поддержка разработки и реализация многозадачности стала необходимой. При этом на применяемые решения влияет значительное число факторов.

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

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

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

    Основные понятия

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

  • Мультипроцессирование - использование нескольких процессоров для одновременного выполнения задач.
  • Мультипрограммирование - одновременное выполнение нескольких задач на одном или нескольких процессорах.
  • В завершение знакомства укажем некоторые термины, определяющие базовые понятия, которыми оперируют операционные системы.

    Мультипроцессирование

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

    (рис 6.1) Разные подходы к реализации мультипроцессирования

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

    Кроме того, очень часто используются многопроцессорные вычислительные системы, в которых используется несколько центральных процессоров. Сложилось несколько подходов к созданию таких компьютеров:

  • наиболее массовыми являются так называемые SMP (Shared Memory Processor или Symmetric MultiProcessor) машины. В таких компьютерах несколько процессоров подключены к общей оперативной памяти и имеют к ней равноправный и конкурентный доступ (см. рис 6.2(рис 6.2) SMP компьютер
  • при необходимости создания систем с качественно большим числом процессоров прибегают к MPP (Massively Parallel Processors) системам. Для этого используют несколько однопроцессорных или SMP-систем, объединяемых с помощью некоторого коммуникационного оборудования в единую сеть (см. рис 6.3(рис 6.3) MPP система
  • иногда используют так называемые NUMA и cc-NUMA архитектуры; они являются компромиссом между SMP и MPP системами: оперативная память является общей и разделяемой между всеми процессорами, но при этом память неоднородна по времени доступа. Каждый процессорный узел имеет некоторый объем оперативной памяти, доступ к которой осуществляется максимально быстро; для доступа к памяти другого узла потребуется значительно больше времени (см. рис 6.4(рис 6.4) NUMA или cc-NUMA система
  • Таким образом, с точки зрения реализации мультипроцессирования, для разработчиков ПО важно иметь представление о том, каковы средства взаимодействия между параллельно работающими ветвями кода - общая память с равноправным или неравноправным доступом, либо некоторая коммуникационная среда с механизмом пересылки данных. Наибольшее распространение получили SMP и MPP системы, соответственно, большинство операционных систем содержат необходимые средства для эффективного управления SMP системами. Для реализации MPP систем, как правило, используются обычные операционные системы на всех узлах и либо обычные сетевые технологии, с применением распространенных стеков протоколов, либо специфичное коммуникационное оборудование со своими собственными драйверами и собственными средствами взаимодействия с приложениями. NUMA системы распространены в меньшей степени, хотя выпускаются серийно. Нормальным при этом является применение массовых операционных систем, рассчитанных на SMP установки, несмотря на то, что это несколько снижает эффективность использования NUMA.

    Windows содержит встроенные механизмы, необходимые для работы на SMP; также возможна установка этой ОС на cc-NUMA системах (современные версии Windows имеют механизмы поддержки cc-NUMA систем). Специальных, встроенных в ОС средств для исполнения приложений на MPP системах в Windows не предусмотрено. Windows предполагает альтернативное применение MPP систем, построенных на обычных сетях, для реализации web- или файловых серверов с балансировкой нагрузки по узлам кластера.

    Мультипрограммирование

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

    Важно подчеркнуть, что мультипрограммирование предполагает управление одновременно выполняющимися приложениями пользователя, а не вообще всяким кодом. Любая реальная вычислительная система должна предусматривать специальные меры для своевременного обслуживания поступающих прерываний, исключений и остановок. Такое обслуживание должно выполняться независимо от работы приложений пользователя и в большинстве случаев имеет абсолютный приоритет над приложениями, так как задержка в обработке подобных событий чревата возникновением неустранимых сбоев и потерь данных. В результате операционные системы предоставляют некоторый механизм, обслуживающий возникающие прерывания и только в промежутках между прерываниями - приложения пользователя. Более того, поскольку аппаратные прерывания происходят в большинстве случаев асинхронно по отношению к приложениям и по отношению к другим прерываниям, то получается так, что система должна содержать два планировщика или диспетчера - один для прерываний, другой для приложений. Работа диспетчера прерываний здесь не рассматривается, поскольку относится сугубо к ядру операционной системы и практически не затрагивает работу приложений.

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

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

    (рис 6.5) Планирование задач

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

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

    Выделяют понятия вытесняющей и невытесняющей многозадачности: в случае невытесняющей многозадачности решение о переключении принимает выполняемая в данный момент задача, а в случае вытесняющей многозадачности такое решение принимается операционной системой (или иным арбитром), независимо от работы активной в данный момент задачи.

    На приведенном графе состояний задачи (см. рис. 6.6) прямая линия от состояния "выполнение" к состоянию "готовность" нарисована пунктиром, чтобы выделить отличие невытесняющей многозадачности от вытесняющей. В случае невытесняющей многозадачности выполняющаяся задача может либо завершиться, либо перейти в состояние "ожидание".

    (рис 6.6) Граф состояния задачи

    И тот, и другой переходы определены логикой работы самой задачи. На графе состояний задачи в случае невытесняющей многозадачности пунктирной линии от состояния "выполнение" к состоянию "готовность" не будет. В случае вытесняющей многозадачности вытеснение осуществляется по решению системы, а не только по инициативе задачи.

    Для невытесняющей многозадачности характерно, что операционная система передает задаче управление и далее ожидает от нее сигнала, информирующего о возможности переключения на другую задачу; сама по себе операционная система выполняемую задачу не прерывает. Именно поэтому невытесняющая многозадачность рассматривается как многозадачность с относительными приоритетами - пока задача сама не сообщит, что настал подходящий для переключения момент, система не сможет передать управление никакой другой, даже высокоприоритетной, задаче.

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

    Характерный пример невытесняющей многозадачности - 16-ти разрядные Windows (включая собственно 16-ти разрядные версии Windows, выполнение 16-ти разрядных приложений в Windows-95, 98, ME и выполнение 16-ти разрядных приложений в рамках одной Windows-машины в NT, 2000, XP и 2003). В таких приложениях операционная система не прерывает выполнение текущей задачи до вызова ею функций типа GetMessage или WaitMessage, во время которых Windows осуществляет при необходимости переключение на другую задачу.

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

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

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

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

    (рис 6.7) Моменты перепланирования задач

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

  • запуск задачи (для возможно скорейшего начала исполнения);
  • досрочное освобождение процессора до исчерпания отведенного кванта (велик шанс, что задача и в этот раз так же быстро отдаст управление);
  • частый вызов операций ввода-вывода (при этом задача чаще находится в ожидании завершения операции, нежели занимает процессорное время);
  • продолжительное ожидание в очереди (приоритет ожидающей задачи часто постепенно начинают увеличивать);
  • и многие другие.
  • Работа планировщика существенно усложняется в случае SMP машин, когда необходимо принимать во внимание привязку задач к процессорам (иногда задаче можно назначить конкретный процессор) и то, на каком процессоре задача выполнялась до того (это позволяет эффективнее использовать кэш-память процессора).

    Реализации Windows NT, 2000, XP, 2003+ предусматривают достаточно развитый и сложный планировщик, учитывающий множество факторов и корректирующий как назначение и длительность отводимых задаче квантов, так и приоритеты задач. При этом планировщик является настраиваемым, и его логика работы несколько отличается в зависимости от настроек системы (некоторые доступны через панель управления) и от назначения системы (работа планировщика различна у серверов и рабочих станций).

    Важно отметить, что Windows является гибкой системой разделения времени с вытесняющей многозадачностью и не может рассматриваться в качестве системы реального времени. Даже те процессы, которые с точки зрения Windows относятся к классу процессов так называемого "реального времени", на самом деле требованиям, предъявляемым к системам реального времени, не удовлетворяют. Такие процессы получат приоритетное распределение процессорного времени и будут обрабатываться планировщиком с учетом их "особого статуса"; однако при этом нельзя гарантировать строгого выполнения временных ограничений. Более того, в силу используемых механизмов управления памятью, нельзя точно предсказать время, необходимое для выполнения той или иной операции. В любой момент времени при самом невинном обращении к какой-либо переменной или функции может потребоваться обработка ошибок доступа, подкачка выгруженных страниц, освобождение памяти и т.д. - то есть действия, время завершения которых предсказать крайне трудно. Фактически можно давать лишь вероятностные прогнозы по времени выполнения той или иной операции. До определенных рамок Windows можно применять в мягких системах реального времени - с достаточно свободными ограничениями, но даже незначительная вероятность превышения временных ограничений иногда просто недопустима.

    Базовая терминология

    В операционных системах сложилось несколько подходов к реализации многозадачности, и, соответственно, принятая в разных операционных системах терминология несколько отличается. Так, обычно разделяют понятия задачи, процесса и потока. При этом понятие задачи является в большей степени историческим, либо очень специфичным. Это понятие сформировалось, когда единицей выделения процессорного времени была сама задача; планировщик же мог только переключать задачи. В современных системах большее распространение получил подход, в котором в рамках одной "задачи" может быть выделено несколько одновременно выполняемых ветвей кода, соответственно термин "задача" заместился терминами "процесс" и "поток".

    Процесс является объектом планирования адресного пространства и некоторых ресурсов, выделенных задаче. Но при этом процесс не является потребителем процессорного времени и не подлежит планированию.

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

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

    В Windows для обозначения этих понятий использованы термины process (процесс), thread (поток) и fiber (волокно). Достаточно часто термин "thread" переводится на русский язык как "нить", а не "поток". Термин "fiber" также может переводиться либо как "нить", либо как "волокно". Поток соответствует потоку ядра и планируется ядром операционной системы, а волокно соответствует потоку пользователя и планируется в приложении пользователя.

    В операционной системе для описания потоков используются объекты двух типов - так называемые дескрипторы и контекст. Дескрипторы содержат информацию, описывающую поток, но не его текущее состояние исполнения. Контекст потока содержит информацию, описывающую непосредственно состояние исполнения потока. Так, например, дескриптор должен содержать переменные окружения, права доступа, назначенные потоку, приоритет, величину кванта и так далее, тогда как контекст должен сохранять информацию о состоянии стека, регистров процессора и т.д. Дескрипторы содержат актуальную в каждый момент информацию, а контекст обновляется в тот момент, когда поток выходит из исполняемого состояния. Из контекста восстанавливается состояние потока при возобновлении исполнения. Пока поток выполняется, содержимое контекста не является актуальным и не соответствует его реальному состоянию.

    Реализация в Windows

    В современных полновесных реализациях Windows (Windows 2000, Windows XP, Windows 2003) планировщик ядра выделяет процессорное время потокам. Управление волокнами возложено на приложения пользователя: Windows предоставляет набор функций, с помощью которых приложение может управлять созданными волокнами. Фактически для волокон реализуется невытесняющая многозадачность средствами приложения; с точки зрения операционной системы, все волокна должны быть созданы в рамках потоков (один поток может быть "расщеплен" на множество волокон средствами приложения) и система никак не вмешивается в их планирование.

    В Windows определен список событий, которые приводят к перепланированию потоков:

  • создание и завершение потока;
  • выделенный потоку квант исчерпан;
  • поток вышел из состояния ожидания;
  • поток перешел в состояние ожидания;
  • изменен приоритет потока;
  • изменена привязка к процессору.
  • В целях уменьшения затрат на планирование потоков несколько изменен граф состояний потока. На рис. 6.6 приведен "классический" вид графа состояний задачи, а на рис. 6.8 - граф состояний потока в Windows. Переход из состояния "готовность" в состояние "выполнение" сделан в два этапа - выбранный к выполнению поток подготавливается к выполнению и переводится в состояние "выбран"; эта подготовка может осуществляться до наступления момента перепланирования, и в нужный момент достаточно просто переключить контекст выполняющегося потока на выбранный.

    (рис 6.8) Граф состояний потока

    Также в два этапа может происходить переход из состояния "ожидание" в "готовность": если ожидание было долгим, то стек потока может быть выгружен из оперативной памяти. В этом случае поток переводится в промежуточное состояние до завершения загрузки стека - в списке готовых к выполнению потоков находятся только те, которые можно начать выполнять без лишнего ожидания.

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

    Процесс выбора потока для выполнения усложняется в случае SMP систем, когда помимо приоритета готового к исполнению потока учитывается, на каком процессоре ранее выполнялся код данного потока.

    В Windows выделяют понятие "идеального" процессора - им назначается процессор, на котором запускается приложение в первый раз. В дальнейшем система старается выполнять код потока именно на этом процессоре - для SMP систем это решение улучшает использование кэш-памяти, а для NUMA систем позволяет, по большей части, ограничиться использованием оперативной памяти, локальной для данного процессора. Заметим, что диспетчер памяти Windows при выделении памяти для запускаемого процесса старается учитывать доступность памяти для назначенного процессора в случае NUMA системы.

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

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

    Управление квантованием

    Квантование потоков осуществляется по тикам системного таймера, продолжительность одного тика составляет обычно 10 или 15 мс, больший по продолжительности тик назначают многопроцессорным машинам. Каждый тик системного таймера соответствует 3 условным единицам; величина кванта может варьироваться от 2 до 12 тиков (от 6 до 36 единиц).

    Параметр реестра HKLM\SYSTEM\CurrentControlSet\Control\PriorityControl\ Win32PrioritySeparation предназначен для управления квантованием. На рис. 6.9 дан формат этого параметра для Windows 2000-2003, а в таблице 6.1 приводятся длительности квантов в условных единицах для разных значений полей параметра Win32PrioritySeparation.

    (рис 6.9) Управление квантованием в Windows (длительность кванта показана в табл. 6.1)
    Длительность кванта
    Короткий квант Длинный квант
    Значение младших 2-х бит параметра Win32PrioritySeparation 01 2 01 2
    Переменная длительность 612 18 1224 36
    Фиксированная длительность 1818 18 3636 36

    Этот параметр может быть изменен с помощью панели управления, однако, лишь в очень ограниченных рамках:

    "System Properties|Advanced|Performance:Settings|Advanced|Adjust for best performance of:" позволяет выбрать только:

  • "applications"

    Короткие кванты переменной длины, значение 0x26 т.е. 10 01 10 (короткие кванты переменной длительности, 18 ед.).

  • "background services"

    Длинные кванты фиксированной длины, значение 0x18 т.е. 01 10 00 (длинные кванты фиксированной длительности, 36 ед.). Более тонкая настройка возможна с помощью редактора реестра.

  • Управление длительностью кванта связано с активностью процесса, которая определяется наличием интерфейса пользователя (GUI или консоль) и его активностью. Если процесс находится в фоновом режиме, то длительность назначенного ему кванта соответствует "нулевым" колонкам таблицы 6.1 (выделены серым цветом; т.е. длительности 6 или 12 - для переменной длины кванта или 18 и 36 - для фиксированной). Когда процесс становится активным, то ему назначается продолжительность квантов, исходя из значения двух младших бит параметра Win32PrioritySeparation в соответствии с приведенной таблицей.

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

    Управление приоритетами

    В Windows выделяется 32 уровня приоритетов. 0 соответствует самому низкому приоритету (с таким приоритетом работает только специальный поток обнуления страниц), 31 - самому высокому. Этот диапазон делится на три части:

  • Приоритет 0 - соответствует приоритету потока обнуления страниц.
  • Приоритеты с 1 по 15 - соответствуют динамическим уровням приоритетов. Большинство потоков работают именно в этом диапазоне приоритетов, и Windows может корректировать в некоторых случаях приоритеты потоков из этого диапазона.
  • Приоритеты с 16 по 31 - соответствуют приоритетам "реального времени". Этот уровень достаточно высок для того, чтобы поток, работающий с таким приоритетом, мог реально помешать нормальной работе других потоков в системе - например, помешать обрабатывать сообщения от клавиатуры и мыши. Windows самостоятельно не корректирует приоритеты этого диапазона.
  • Для некоторого упрощения управления приоритетами в Windows выделяют "классы приоритета" (priority class), которые задают базовый уровень приоритета, и "относительные приоритеты" потоков, которые корректируют указанный базовый уровень. Операционная система предоставляет набор функций для управления классами и относительными приоритетами потоков.

    Планировщик операционной системы также может корректировать уровень приоритета (из диапазона 1-15), однако базовый уровень (т.е. класс) не может быть изменен. Такая коррекция приоритета выполняется в случае:

  • Завершения операции ввода-вывода - в зависимости от устройства, приоритет повышается на 1 - 8 уровней.
  • По окончании ожидания события или семафора (см. далее) - на один уровень.
  • При пробуждении GUI потоков - на 2 уровня.
  • По окончании ожидания потоком активного процесса (определяется по активности интерфейса) - на величину, указанную младшими 2 битами параметра Win32PrioritySeparation (см. управление длительностью кванта).
  • В случае коррекции приоритета по одной из перечисленных причин, повышенный приоритет начинает постепенно снижаться до начального уровня потока - с каждым тиком таймера на один уровень.

    Еще один случай повышения приоритета (вместе с увеличением длительности кванта) - процесс долгое время не получал процессорного времени. В этой ситуации система раз в 3-4 секунды назначает процессу приоритет, равный 15, и квант удвоенной длительности. По истечении этого кванта приоритет возвращается к прежнему значению и восстанавливается рекомендуемая длительность кванта.

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

    Соответствие классов приоритета и относительных приоритетов потоков уровням
    Уровень Класс приоритета (задает базовый уровень приоритета)
    REALTIME 24 HIGH 13 ABOVE_NORMAL 10 NORMAL BELOW_NORMAL 6 IDLE 4
    Foreground 9 Normal 8 Background 7
    31 TIME_CRITICAL

    Уровни приоритета с 16 по 31 отведены только для класса REALTIME_PRIORITY_CLASS

    Не рекомендуется создавать потоки с таким классом приоритета, так как это может повлиять на обработку сообщений от клавиатуры, мыши, сохранение на диске данных кэша и т.д.
    30 6
    29 5
    28 4
    27 3
    26 HIGHEST
    25 ABOVE_NORMAL
    24 NORMAL (24)
    23 BELOW_NOR-MAL
    22 LOWEST
    21 -3
    20 -4
    19 -5
    18 -6
    17 -7
    16 IDLE
    15 TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL TIME_CRI-TICAL
    14 ABOVE_NOR-MAL
    13 NORMAL (13)
    12 BELOW_NOR-MAL HIGHEST
    11 LOWEST ABOVE_NOR-MAL HIGHEST
    10 NORMAL (10) ABOVE_NOR-MAL HIGHEST
    9 BELOW_NOR-MAL NORMAL (9) ABOVE_NOR-MAL HIGHEST
    8 LOWEST BELOW_NOR-MAL NORMAL (8) ABOVE_NOR-MAL HIGHEST
    7 LOWEST BELOW_NOR-MAL NORMAL (7) ABOVE_NOR-MAL
    6 LOWEST BELOW_NOR-MAL NORMAL (6) HIGHEST
    5 LOWEST BELOW_NOR-MAL ABOVE_NOR-MAL
    4 LOWEST NORMAL (4)
    3 BELOW_NOR-MAL
    2 LOWEST
    1 IDLE IDLE IDLE IDLE IDLE IDLE IDLE
    0 приоритет потока обнуления страниц

    В зависимости от настройки планировщика, NORMAL_PRIORITY_CLASS с базовым уровнем приоритета 8 может быть "расщеплен" на два базовых уровня - для потоков активных процессов (базовый уровень 9) и для потоков фоновых процессов (базовый уровень 7). Для класса HIGH_PRIORITY_CLASS относительные приоритеты потока THREAD_PRIORITY_HIGHEST и THREAD_PRIORITY_TIME_CRITICAL дают одинаковое значение приоритета 15.

    Вернуться к учебному плану