Билет 32. Базовые приоритеты процессов, управление
Голодающий поток – готовый к выполнению поток, не получивший квант времени в течение 300 ИСТ
Голодающий поток получает 2 кванта времени с приоритетом 15, далее существует в системе со своим приоритетом еще 300 ИСТ, после чего получает 2 кванта с приоритетом 15 и т. д.
Уровни приоритета назначаются с учетом двух разных точек зрения - Windows API и ядра Windows.
Windows API сначала упорядочивает процессы по классам приоритета, назначенным при их создании [Real-time (реального времени), High (высокий), Above Normal (выше обычного), Normal (обычный), Below Normal (ниже обычного) и Idle (простаивающий)], а затем — по относительному приоритету индивидуальных потоков в рамках этих процессов [Time-critical (критичный по времени), Highest (наивысший), Above-normal (выше обычного), Normal (обычный), Below-normal (ниже обычного), Lowest (наименьший) и Idle (простаивающий)].
Базовый приоритет каждого потока в Windows API устанавливается, исходя из класса приоритета его процесса и относительного приоритета самого потока. Если у процесса только одно значение приоритета (базовое), то у каждого потока их два: текущее и базовое. Решения, связанные с планированием, принимаются на основе текущего приоритета. В определенных обстоятельствах система может на короткое время повышать приоритеты потоков в динамическом диапазоне (1-15). Windows никогда не изменяет приоритеты потоков в диапазоне реального времени (16-31), поэтому у таких потоков базовый приоритет идентичен текущему.
Обычно базовый приоритет процесса (а значит, и базовый приоритет первичного потока) по умолчанию равен значению из середины диапазонов приоритетов процессов (24, 13, 10, 8, 6 или 4). Однако базовый приоритет некоторых системных процессов (например, диспетчера сеансов, контроллера сервисов и сервера локальной аутентификации) несколько превышает значение по умолчанию для класса Normal (8). Более высокий базовый приоритет по умолчанию обеспечивает запуск потоков этих процессов с приоритетом выше 8.
Динамические приоритеты позволяют повысить реактивность системы, т.к. реагируют на изменения ситуации, и начальное значение приоритета процесса может быть изменено на новое, более подходящее значение.
Динамическое повышение приоритета
Windows может динамически повышать значение текущего приоритета потока в одном из пяти случаев:
• после завершения операций ввода-вывода;
• по окончании ожидания на событии или семафоре исполнительной системы;
•по окончании операции ожидания потоками активного процесса;
•при пробуждении GUI-потоков из-за операций с окнами;
• если поток, готовый к выполнению, задерживается из-за нехватки процессорного времени.
Динамическое повышение приоритета предназначено для оптимизации общей пропускной способности и отзывчивости системы, а также для устранения потенциально «нечестных» сценариев планирования. Однако, как и любой другой алгоритм планирования, динамическое повышение приоритета — не панацея, и от него выигрывают не все приложения.
ПРИМЕЧАНИSWindows никогда не увеличивает приоритет потоков в диапазоне реального времени (16–31). Поэтому планирование таких потоков по отношению к другим всегда предсказуемо. Windows считает: тот, кто использует приоритеты реального времени, знает, что делает.
Динамическое повышение приоритета после завершения ввода-вывода
Windows временно повышает приоритет потоков по окончании определенных операций ввода-вывода, поэтому у потоков, ожидавших завершения таких операций, больше шансов немедленно возобновить выполнение и обработать полученные данные. Вспомните: после пробуждения потока оставшийся у него квант уменьшается на одну единицу, так что потоки, ожидавшие завершения ввода-вывода, не получают неоправданных преимуществ. Хотя рекомендованные приращения в результате динамического повышения приоритета определены в заголовочных файлах DDK (ищите строки «#define IO» в Wdm.h или Ntddk.h; эти же значения перечислены в таблице 6-17), реальное приращение определяется драйвером устройства. Именно драйвер устройства указывает — через функцию ядраIoCompleteRequest — на необходимость динамического повышения приоритета после выполнения запроса на ввод-вывод. Заметьте, что для запросов на ввод-вывод, адресованных устройствам, которые гарантируют меньшее время отклика, предусматриваются большие приращения приоритета.
Приоритет потока всегда повышается относительно базового, а не текущего уровня. Как показано на рис. 6-22, после динамического повышения приоритета поток в течение одного кванта выполняется с повышенным уровнем приоритета, после чего приоритет снижается на один уровень и потоку выделяется еще один квант. Этот цикл продолжается до тех пор, пока приоритет не снизится до базового. Поток с более высоким приоритетом все равно может вытеснить поток с повышенным приоритетом, но прерванный поток должен полностью отработать свой квант с повышенным приоритетом до того, как этот приоритет начнет понижаться.
Как уже отмечалось, динамическое повышение приоритета применяется только к потокам с приоритетом динамического диапазона (0-15). Независимо от приращения приоритет потока никогда не будет больше 15. Иначе говоря, если к потоку с приоритетом 14 применить динамическое повышение на 5 уровней, его приоритет возрастет лишь до 15. Если приоритет потока равен 15, он остается неизменным при любой попытке его повышения.
Динамическое повышение приоритета по окончании ожидания событий и семафоров
Когда ожидание потока на событии исполнительной системы или объекте «семафор» успешно завершается (из-за вызова SetEvent, PulseEvent или ReleaseSemaphore), его приоритет повышается на 1 уровень (см. значения EVENT_INCREMENT и SEMAPHORE_INCREMENT в заголовочных файлах DDK). Причина повышения приоритета потоков, закончивших ожидание событий или семафоров, та же, что и для потоков, ожидавших окончания операций ввода-вывода: потокам, блокируемым на событиях, процессорное время требуется реже, чем остальным. Такая регулировка позволяет равномернее распределять процессорное время.
B данном случае действуют те же правила динамического повышения приоритета, что и при завершении операций ввода-вывода (см. предыдущий раздел).
K потокам, которые пробуждаются в результате установки события вызовом специальных функцийNtSetEventBoostPriority (используется в Ntdll.dll для критических секций) и KeSetEventBoostPriority(используется для ресурсов исполнительной системы и блокировок с заталкиванием указателя) повышение приоритета применяется особым образом. Если поток с приоритетом 13 или ниже, ждущий на событии, пробуждается в результате вызова специальной функции, его приоритет повышается до приоритета потока, установившего событие, плюс 1. Если длительность его кванта меньше 4 единиц, она приравнивается 4 единицам. Исходный приоритет восстанавливается по истечении этого кванта.
Динамическое повышение приоритета потоков активного процесса после выхода из состояния ожидания
Всякий раз, когда поток в активном процессе завершает ожидание на объекте ядра, функция ядраKiUnwaitThread динамически повышает его текущий (не базовый) приоритет на величину текущего значения PsPrioritySeparation. (Какой процесс является активным, определяет подсистема управления окнами.) Как было сказано в разделе «Управление величиной кванта» ранее в этой главе,PsPrioritySeparation представляет собой индекс в таблице квантов (байтовом массиве), с помощью которой выбираются величины квантов для потоков активных процессов. Однако в данном случаеPsPrioritySeparation используется как значение, на которое повышается приоритет.
Это увеличивает отзывчивость интерактивного приложения по окончании ожидания. B результате повышаются шансы на немедленное возобновление его потока — особенно если в фоновом режиме выполняется несколько процессов с тем же базовым приоритетом.
B отличие от других видов динамического повышения приоритета этот поддерживается всеми системами Windows, и его нельзя отключить даже через Windows-функцию SetThreadPriorityBoost.
Динамическое повышение приоритета после пробуждения GUI-потоков
Приоритет потоков, владеющих окнами, дополнительно повышается на 2 уровня после их пробуждения из-за активности подсистемы управления окнами, например при получении оконных сообщений. Подсистема управления окнами (Win32k.sys) повышает приоритет, вызывая KeSetEvent для установки события, пробуждающего GUI-поток. Приоритет повышается по той же причине, что и в предыдущем случае, — для создания преимуществ интерактивным приложениям.
Билет 33. Цели и средства синхронизации. Классификация потоков по способу взаимодействия. Необходимость синхронизации. Примеры выполнения параллельных конкурирующих потоков, работающих с общей переменной и с наборами разделяемых данных.
Потребность в синхронизации потоков возникает только в мультипрограммной ОС и связана с совместным использованием несколькими процессами аппаратных и информационных ресурсов ВС. Выполнение потока в мультипрограммной среде всегда имеет асинхронный характер. Очень сложно с полной определенностью сказать, на каком этапе будет находиться процесс в определенный момент времени. Т.к. исходные данные в разные моменты запуска задачи могут быть разными, то и время выполнения отдельных этапов и задачи в целом является весьма неопределенной величиной. Также неопределенным является время выполнения программы в мультипрограммной системе. Потоки в общем случае (когда программист не предпринял специальных мер по синхронизации) протекают независимо, асинхронно друг другу. Любое взаимодействие процессов (потоков), связанное с разделением ресурсов или обменом данными, требует их синхронизации. Синхронизация заключается в согласовании скоростей процессов (потоков) путем приостановки одного или нескольких из них до наступления некоторого события и последующей активации при наступлении этого события. (Задача «поставщик-потребитель»). При совместном использовании аппаратных средств синхронизация совершенно необходима. Часто нужна синхронизация с событиями, внешними по отношению к ВС, например, реакции на нажатие комбинации клавиш Ctrl+C.
Средства. Для синхронизации потоков прикладных программ программист может использовать как собственные средства и приемы синхронизации, так и средства ОС. Например, два потока одного прикладного процесса могут координировать свою работу с помощью доступной для них обоих глобальной логической переменной, которая устанавливается в единицу при осуществлении некоторого события, например, выработки одним потоком данных, нужных для продолжения работы другого. Но во многих случаях эффективными и даже единственно возможными являются средства синхронизации, предоставляемые ОС в форме системных вызовов. Так, потоки, принадлежащие разным процессам, не имеют возможности вмешиваться каким-либо образом в работу друг друга. Без посредничества ОС они не могут приостановить друг друга или оповестить о произошедшем событии. Средства синхронизации используются ОС не только для синхронизации прикладных процессов, но и для ее внутренних нужд. Обычно разработчики ОС предоставляют в распоряжение прикладных и системных программистов широкий спектр средств синхронизации. Эти средства могут образовывать иерархию, когда на основе более простых средствах строятся более сложные, кроме того, подобные средства могут быть функционально специализированными, например, средства для синхронизации потоков одного процесса, средства для синхронизации потоков разных процессов для обмена данными и т.д. Часто функциональные возможности разных системных вызовов синхронизации перекрываются, так что для решения одной задачи программист может воспользоваться несколькими вызовами в зависимости от своих личных предпочтений.