![](/user_photo/2706_HbeT2.jpg)
Лекция 5
Распределение процессорного времени между потоками
Система выделяет процессорное время всем активным потокам, исходя из их уровней приоритета, которые варьируются от 0 до 31.
Низший уровень является зарезервированным и назначается специальному системному потоку обнуления страниц.
Когда система подключает процессор к потоку, он обрабатывает потоки с одинаковым приоритетом как равноправные. Как только все потоки с данным приоритетом получат по кванту и при условии, что они больше не требуют процессорного времени ОС переходит к потокам с более низким приоритетом.
Существует вероятность, что процессор постоянно обрабатывает потоки, например с приоритетом 31. Значит у потоков с более низким приоритетом нет шансов на подключение к процессору. Такая ситуация называется перегрузкой(starvation - зависание). Но вероятность такой ситуации мала. В обычных условиях потоки зачастую просто простаивают.
Допустим, что исполняется поток с приоритетом 5. В это время потоку с более высоким приоритетом понадобился процессор. ОС немедленно остановит поток с низким приоритетом, даже если не истек отведенный ему квант времени, после чего подключит поток с более высоким приоритетом, выделив ему полный квант времени.
Потоки с более высоким приоритетом всегда вытесняют потоки с более низким приоритетом, независимо от того, исполняются последние или нет.
Уровень приоритета присваивается в два этапа:
процессу присваивается определенный класс приоритета
потокам, принадлежащим процессу, присваиваются относительные уровни приоритета.
Классы приоритета процесса:
Класс |
Флаг |
Уровень |
простаивающий(idle) |
IDLE_PRIORITY_CLASS |
4 |
обычный(normal) |
NORMAL_PRIORITY_CLASS |
8 |
высокий(high) |
HIGH_PRIORITY_CLASS |
13 |
реального времени(realtime) |
REALTIME_PRIORITY_CLASS |
24 |
Большинство приложений в основном относятся к приложениям с обычным классом приоритета. Такие процессы ведут себя несколько иначе:
Windows NT увеличивает квант времени потокам активного процесса. Например: потоки обычного процесса получают 15 мс процессорного времени, до тех пор, пока не становятся активными. В этом состоянии им достается 45 мс (диалог Панель управления\Система\Perfomance позволяет регулировать во сколько раз необходимо увеличить квант).
Windows 95 повышает уровень потока на 1 для активного процесса. Когда процесс уходит в "фон" уровень потока снижается на 1.
Причина таких изменений в активных процессах связана с тем, что система добивается быстрого реагирования на пользовательский ввод.
Приоритет idle идеален для приложений, занимающихся мониторингом системы (например, программы - экранные заставки).
Класс приоритета high следует использовать только в крайней необходимости (например: Explorer).
Приоритет realtime практически никогда не используется, кроме случаев работы с нестандартным оборудованием или когда программа выполняет быстротечную операцию, которую нельзя прерывать.
Узнать о приоритете процесса можно с помощью функции
function GetPriorityClass(hProcess: THandle): DWORD;
а установить
function SetPriorityClass(hProcess: THandle; dwPriorityClass: DWORD): BOOL;
Когда создается новый поток, уровень его приоритета соответствует классу процесса. Но существует возможность повысить или понизить уровень приоритета отдельного потока относительно процесса.
function SetThreadPriority(hThread:THandle;nPriority:Integer): BOOL;
nPriority может принимать следующие значения
Значение |
Описание |
THREAD_PRIORITY_LOWEST |
-2 единицы |
THREAD_PRIORITY_BELOW_NORMAL |
-1 единица |
THREAD_PRIORITY_NORMAL |
0 |
THREAD_PRIORITY_ABOVE_NORMAL |
+1 единицы |
THREAD_PRIORITY_HIGHEST |
+2 единицы |
Повторные вызовы SetThreadPriority не дают кумулятивного эффекта.
Следующая функция позволяет узнать относительный приоритет процесса
function GetThreadPriority(hThread: THandle): Integer;
Существует возможность задержать выполнение потока как при его создании (флаг CREATE_SUSPENDED) так и с помощью вызова функции function SuspendThread(hThread:THandle):DWORD, которая увеличивает счетчик простоев потока. При удачном выполнении функция возвращает предыдущее значение счетчика простоев или $FFFFFFFF. Чтобы возобновить выполнение потока необходимо из другого потока вызвать функцию function ResumeThread(hThread:THandle):DWORD, которая уменьшит счетчик простоев на единицу и если он будет равен 0, запустит поток на выполнение. Приостановить поток можно не более чем 127 раз.