2.Внутреннее устройство Windows (гл. 5-7)
Шрифт:
Динамическое повышение приоритета предназначено для оптимизации общей пропускной способности и отзывчивости системы, а также для устранения потенциально «нечестных» сценариев планирования. Однако, как и любой другой алгоритм планирования, динамическое повышение приоритета — не панацея, и от него выигрывают не все приложения.
ПРИМЕЧАНИЕ Windows никогда не увеличивает приоритет потоков в диапазоне реального времени (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.
ЭКСПЕРИМЕНТ: наблюдение за динамическим изменением приоритета потока активного процесса
Увидеть механизм повышения приоритета в действии позволяет утилита CPU Stress (входит в состав ресурсов и Platform SDK).
1. B окне Control Panel (Панель управления) откройте апплет System (Система) или щелкните правой кнопкой мыши значок My Computer (Мой компьютер), выберите команду Properties (Свойства) и перейдите на вкладку Advanced (Дополнительно). Если вы используете Windows 2000, щелкните кнопку Performance Options (Параметры быстродействия) и выберите переключатель Applications (Приложений). B случае Windows XP или Windows Server 2003 щелкните кнопку Options (Параметры) в разделе Performance (Быстродействие), откройте вкладку Advanced (Дополнительно) и выберите переключатель Programs (Программ). B итоге PsPrioritySeparation получит значение 2.
2. Запустите Cpustres.exe.
3. Запустите Windows NT 4 Performance Monitor (Perfmon4.exe на компакт-диске ресурсов Windows 2000). Для эксперимента нужна имен-
но эта устаревшая версия, поскольку она способна запрашивать значения счетчиков производительности с более высокой частотой, чем оснастка Performance (Производительность), которая запрашивает такие значения не чаще, чем раз в секунду.
4. Щелкните на панели инструментов кнопку Add Counter (или нажмите клавиши Ctrl+I), чтобы открыть диалоговое окно Add To Chart.