Вы находитесь на странице: 1из 102

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

Системное программирование
Содержание
1. Определение потока
2. Однопоточные и многопоточные
процессы
3. Структура потока
4. Повторно входящие или
реентерабельные функции
5. Запуск потока
6. Завершение потока
7. Приостановка потока

И.В. Птицына & Б.Ф. Мишнев 2


1. Определение потока

И.В. Птицына & Б.Ф. Мишнев 3


4
Поток (нить, thread, задача, task)
• Это независимая единица выполнения
программы в контексте процесса.
• Последовательность выполнения
инструкций программы называется
потоком управления внутри программы.
• Поток управления можно представить как
нить в программе, на которую нанизаны
инструкции, выполняемые
микропроцессором.

И.В. Птицына & Б.Ф. Мишнев 4


Определение
• Процесс – это логическое представление
работы, которую должна выполнить ОС
• Поток – это единица исполнения,
отдельный счетчик команд или
подлежащая планированию сущность
внутри процесса.

И.В. Птицына & Б.Ф. Мишнев 5


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

И.В. Птицына & Б.Ф. Мишнев 6


2. Однопоточные и
многопоточные процессы

И.В. Птицына & Б.Ф. Мишнев 7


Как надо потоки использовать
•Потоки эффективны при условии
соблюдения нескольких
элементарных правил и следования
определенным моделям
программирования
•Процессы могут быть как
однопоточными, так и
многопоточными

И.В. Птицына & Б.Ф. Мишнев 8


Напоминание!
•Процессом называется исполняемое
на компьютере приложение
(программа) вместе со всеми
ресурсами, которые требуются для
его исполнения.

И.В. Птицына & Б.Ф. Мишнев 9


Однопоточные и многопоточные
программы

• Программа является многопоточной, если


в ней может одновременно существовать
несколько потоков. Сами потоки в этом
случае называются параллельными.
• Если в программе одновременно может
существовать только один поток, то такая
программа называется однопоточной.

И.В. Птицына & Б.Ф. Мишнев 10


И.В. Птицына & Б.Ф. Мишнев 11
Пример однопоточной программы
#include <iostream.h>
int sum(int a, int b) { return a + b; }

int main()
{
int a, b; int с = 0;
cout « "Input two integers: "; cin » 'a » b;
с = sum (a, b) ;
cout « "Sum = " « с « endl; return 0;
}

И.В. Птицына & Б.Ф. Мишнев 12


Параллельность?
• Если после вызова функции sum функция
main не ждет возвращения значения из
функции sum, а продолжает выполняться,
то мы получим программу, состоящую из
двух потоков, один из которых
определяется функцией main, а второй —
функцией sum.

И.В. Птицына & Б.Ф. Мишнев 13


Возможная проблема?
• В этом случае не гарантируется, что поток
main выведет сумму чисел а и b, т. к.
инструкция вывода значения суммы
может отработать раньше, чем поток sum
вычислит эту сумму.

И.В. Птицына & Б.Ф. Мишнев 14


15
Недостатки однопоточных процессов
• Переключение между выполняющимися
процессами потребляет заметную долю
временных и других ресурсов ОС
• Между процессами существует лишь
слабая взаимосвязь, а организация
разделения ресурсов, например, открытых
файлов, вызывает затруднения

И.В. Птицына & Б.Ф. Мишнев 15


Недостатки однопоточных процессов 16

(продолжение)

• С использованием только однопоточных


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

И.В. Птицына & Б.Ф. Мишнев 16


Проблемы, связанные с 17

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

И.В. Птицына & Б.Ф. Мишнев 17


18
Проблемы (продолжение)
• Разделение потоками общей памяти и других
ресурсов в контексте одного процесса может
стать причиной нарушения условий
состязаний между процессами и вызвать
блокирование некоторых из них.

И.В. Птицына & Б.Ф. Мишнев 18


3. Структура потока

И.В. Птицына & Б.Ф. Мишнев 19


Каждый поток имеет:

• Уникальный идентификатор потока;


• Содержимое набора регистров процессора,
отражающих состояние процессора;
• Два стека, один из которых используется
потоком при выполнении в режиме ядра, а
другой - в пользовательском режиме;
• Закрытую область памяти, называемую
локальной памятью потока (thread local storage,
TLS) и используемую подсистемами, run-time
библиотеками и DLL.

И.В. Птицына & Б.Ф. Мишнев 20


Контекст потока
• Содержимое памяти, к которой поток имеет
доступ во время своего исполнения, называется
контекстом потока.
• Регистры, стек, и собственная область памяти и
являются контекстом (context) потока.
• При вызове потока, вызывающий процесс может
передать ему аргумент

И.В. Птицына & Б.Ф. Мишнев 21


22
Память потока (продолжение)
• Каждый поток может распределять индексы
собственных локальных областей хранения
(Thread Local Storage, TLS), а так же считывать и
устанавливать значения TLS.
• Собственная область памяти, предназначенная
для использования подсистемами,
библиотеками периода выполнения и
динамически подключаемыми библиотеками
(DLL).

И.В. Птицына & Б.Ф. Мишнев 22


23

TLS - Thread Local Storage

• TLS представляют в распоряжение потоков


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

И.В. Птицына & Б.Ф. Мишнев 23


Структура процесса

И.В. Птицына & Б.Ф. Мишнев 24


Память потока

И.В. Птицына & Б.Ф. Мишнев 25


4. Повторно входящие или
реентерабельные функции

И.В. Птицына & Б.Ф. Мишнев 26


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

И.В. Птицына & Б.Ф. Мишнев 27


Повторно входящая или
реентерабельная функция

• Не использует глобальные переменные,


значения которых изменяются параллельно
исполняемыми потоками;
• Не использует статические переменные,
определенные внутри функции;
• Не возвращает указатель на статические
данные, определенные внутри функции.

И.В. Птицына & Б.Ф. Мишнев 28


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

И.В. Птицына & Б.Ф. Мишнев 29


5. Запуск потока

И.В. Птицына & Б.Ф. Мишнев 30


31
Запуск потока. CreateThread
• Указывается начальный адрес потока в коде
процесса
• Указывается размер стека и необходимое
пространство стека будет выделено из
виртуального адресного пространства процесса.
размер стека по умолчанию равен размеру стека
основного потока (обычно 1 Мбайт).
первоначально для стека отводится одна
страница. Новые страницы стека выделяются по
мере надобности до тех пор, пока стек не
достигнет своего максимального размера, поэтому
не сможет больше расти.
• Задается указатель на аргумент, передаваемый
потоку - тот аргумент может быть чем угодно и
должен интерпретироваться самим потоком
• Функция возвращает значение идентификатора
(ID) и дескриптор потока. В случае ошибки
возвращаемое значение равно NULL
И.В. Птицына & Б.Ф. Мишнев 31
32
Заголовок функции CreateThread
HANDLE WINAPI CreateThread (
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId );

после вызова этой функции для создания нового


потока функция возвращает дескриптор нового
объекта потока. этот дескриптор используется для
управления нитью, а кроме того, он представляет
вызывающему процессу возможность удаления
нити, если в этом возникает потребность.
И.В. Птицына & Б.Ф. Мишнев 32
33
Параметры функции CreateThread
• lpThreadAttributes - дескриптор защиты,
который обуславливает, может ли
возвращенный дескриптор быть
унаследован дочерними процессами.
• dwStackSize – если 0, то размер стека по
умолчанию соответствует размеру стека
основного потока ( 1 Мбайт)

И.В. Птицына & Б.Ф. Мишнев 33


34
Параметры функции (продолжение)
• lpParameter – указатель, передаваемый
потоку в качестве аргумента, который
обычно интерпретируется потоком как
указатель на структуру аргумента.
• dwCreationFlags - флаги, которые
управляют созданием потока.

И.В. Птицына & Б.Ф. Мишнев 34


35
Параметр dwCreationFlags
• Если установлен флажок CREATE_SUSPENDED,
создается поток в состоянии ожидания и не
запускается до тех пор, пока не будет
вызвана функция ResumeThread (проверяет
счет времени приостановки работы
подчиненного потока).
• Если это значение нулевое, поток запускается
немедленно после создания.

И.В. Птицына & Б.Ф. Мишнев 35


36
Параметры функции (окончание)
• lpThreadId – принимает идентификатор
нового потока (указатель на переменную,
которая принимает идентификатор нового
потока).
• pStartAddress – указатель на начальный
адрес потока. Как правило, это адрес
функции ThreadProc, код которой
исполняется потоком.

И.В. Птицына & Б.Ф. Мишнев 36


37
Заголовок функции потока:
DWORD WINAPI ThreadProc (LPDWORD
lpData)
• lpData - данные потока пересылаемые в
функцию, которая использует параметр
lpParameter функции CreateThread
• Функция должна возвратить значение,
которое указывает ее успех или неудачу.

И.В. Птицына & Б.Ф. Мишнев 37


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

И.В. Птицына & Б.Ф. Мишнев 38


39
Идентификация потоков
• HANDLE GetCurrentThread (VOID);
• HANDLE GetCurrentThreadID(VOID);

И.В. Птицына & Б.Ф. Мишнев 39


6. Состояние потока

И.В. Птицына & Б.Ф. Мишнев 40


41

Состояние потоков

Ирина Птицына & Борис Мишнев 41


42
Состояние потока

• состояние выполнения (running state);


• состояние ожидания (wait state) ( блокированные
(blocked) или спящие(sleeping);
• состояние готовности (ready state);
• состояние простоя (standby state);
• промежуточное переходное состояние (transition
state), поток пробуждается (wakes);
• приостановленное состояние (suspended);
• состояние завершения (terminate state);

Ирина Птицына & Борис Мишнев 42


Состояние выполнения
• Поток находится в состоянии выполнения (running
state), если она фактически выполняется процессором. В
многопроцессорных системах в состоянии выполнения
могут находиться одновременно несколько потоков.

И.В. Птицына & Б.Ф. Мишнев 43


Состояние ожидания
• Планировщик переводит поток в состояние
ожидания (wait state), если он выполняет
функцию ожидания несигнализирующих
объектов, например, потоков или процессов,
или перехода в сигнальное состояние объектов
синхронизации. Операции ввода/вывода также
будут ожидать завершения передачи дисковых
или иных данных, но ожидание может быть
вызвано и другими многочисленными
функциями. О потоках, находящихся в состоянии
ожидания, нередко говорят как
о блокированных (blocked) или спящих (sleeping).

И.В. Птицына & Б.Ф. Мишнев 44


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

И.В. Птицына & Б.Ф. Мишнев 45


• После истечения кванта времени, отведенного
выполняющемуся потоку, планировщик без ожидания
переводит его в состояние готовности. В результате
выполнения функции Sleep(0) поток также будет
переведен из состояния выполнения в состояние
готовности.
• Планировщик переводит ожидающий поток в состояние
готовности сразу же, как только соответствующие
дескрипторы оказываются в сигнальном состоянии, хотя
при этом поток фактически проходит через
промежуточное переходное состояние (transition state).
В подобных случаях принято говорить о том, что поток
пробуждается (wakes).

И.В. Птицына & Б.Ф. Мишнев 46


Возможность выбора процессора
• Обычно, в соответствии с приведенным описанием,
планировщик помещает поток, находящийся в состоянии
готовности, на любой доступный процессор.
Программист может указать маску родства
процессоров (processor affinity mask) для потока,
предоставляя потоку процессоры, на которых он может
выполняться. Используя этот способ, программист может
распределять процессоры между потоками.
Соответствующими функциями являются
SetProcessorAffinityMask и GetProcessorAffinityMask.
• Функция SetThreadIdealProcessor позволяет указать
предпочтительный процессор, подлежащий
использованию планировщиком при первой же
возможности.

И.В. Птицына & Б.Ф. Мишнев 47


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

И.В. Птицына & Б.Ф. Мишнев 48


Состояние завершения
• Поток переходит в состояние
завершения (terminated state) тогда, когда
его выполнение завершается, и остается в
этом состоянии до тех пор, пока остается
открытым хотя бы один из ее
дескрипторов. Это позволяет другим
потокам запрашивать состояние данного
потока и его код завершения.

И.В. Птицына & Б.Ф. Мишнев 49


Определение состояния потока
• Не существует способа, позволяющего
программе определить состояние другого
потока (разумеется, если поток
выполняется, то он находится в состоянии
выполнения, и поэтому ему нет никакого
смысла определять свое состояние).
• Даже если бы такой способ и существовал,
то состояние потока может измениться
еще до того, как опрашивающий поток
успеет предпринять какие-либо действия в
ответ на полученную информацию.
И.В. Птицына & Б.Ф. Мишнев 50
Ожидание конечного интервала 51

времени
• Функция Sleep приостанавливает работу по выполнению
текущего потока на заданный промежуток времени.
VOID Sleep( DWORD dwMillseconds )

• dwMilliseconds
• [in] Минимальный интервал времени, в миллисекундах,
на которое приостанавливается выполняемая работа.0
• INFINITE

• BOOL SwitchToThread().

Ирина Птицына & Борис Мишнев 51


Функция Sleep - параметры

Параметры
• dwMilliseconds
• [in] Минимальный интервал времени, в миллисекундах, на
которое приостанавливается выполняемая работа.
• Значение нуль заставляет поток оставить остаток своего кванта
машинного времени любому другому потоку равного
приоритета, который является готовым к запуску. Если нет
никаких других потоков равного приоритета, готовых к запуску,
функция немедленно возвращает значение и поток продолжает
выполнение.
• Значение БЕСКОНЕЧНО (INFINITE) вызывает бесконечную
задержку.
• Эта функция не возвращает значений.

Ирина Птицына & Борис Мишнев 52


Функция BOOL SwitchToThread().
• Синтаксис
BOOL SwitchToThread(VOID)
• Если вызов функции SwitchToThread заставляет
операционную систему переключить выполнение в
другой поток, величина возвращаемого значения - не
ноль.
• Если нет других потоков, готовых к исполнению кода,
операционная система не переключает выполнение в
другой поток, а величина возвращаемого значения -
ноль.

Ирина Птицына & Борис Мишнев 53


7. Завершение потока

И.В. Птицына & Б.Ф. Мишнев 54


Завершение потоков
Поток завершается если
• Функция потока возвращает управление.
• Поток самоуничтожается, вызвав ExitThread.
• Другой поток данного или стороннего процесса
вызывает TerminateThread.
• Завершается процесс, содержащий данный
поток.

И.В. Птицына & Б.Ф. Мишнев 55


Правильное завершение потока
• Надо дать функции потока завершиться и
вернуть управление системе.
• Корректно завершиться поток может лишь
самостоятельно.
• Он должен сам вызвать ExitThread
(неважно, сделает он это явно или неявно,
например return), предварительно
освободив ресурсы.

И.В. Птицына & Б.Ф. Мишнев 56


Как завершить процесс?
• Если, в процессе (приложении) есть набор
рабочих потоков, то их необходимо
остановить перед выходом из приложения
• «Главный» поток должен передать всем
рабочим потокам сигнал о том, что «пора
закругляться».
• Это вопрос синхронизации потоков.

И.В. Птицына & Б.Ф. Мишнев 57


Функции завершения потока
• Поток завершается вызовом функции ExitThread,
которая имеет следующий прототип:
VOID ExitThread( DWORD dwExitCode // код
завершения потока );
• При выполнении этой функции система
посылает динамическим библиотекам, которые
загружены процессом, сообщение
dll_thread_detach, которое говорит о том, что
поток завершает свою работу.

И.В. Птицына & Б.Ф. Мишнев 58


Завершение другого потока
• Один поток может завершить другой поток,
вызвав функцию TerminateThread, которая имеет
следующий прототип:
BOOL TerminateThread( HANDLE
hThread, // дескриптор потока
DWORD dwExitThread // код завершения потока
);
• В случае успешного завершения функция
TerminateThread возвращает ненулевое
значение, В ПРОТИВНОМ случае — FALSE.

И.В. Птицына & Б.Ф. Мишнев 59


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

И.В. Птицына & Б.Ф. Мишнев 60


Использование функции
TerminateThread
• TerminateThread предназначена не для
завершения, а для аварийной остановки
потока.
• Используется, когда завершить поток
корректно нет возможности.
• Насильственное «убийство» потоков
грозит, в первую очередь, утечкой
ресурсов.

И.В. Птицына & Б.Ф. Мишнев 61


7. Приостановка потока

И.В. Птицына & Б.Ф. Мишнев 62


Приостановка потоков
• Каждый созданный поток имеет счетчик
приостановок, максимальное значение которого
равно MAXIMUM_SUSPEND_COUNT.
• Счетчик приостановок показывает, сколько раз
исполнение потока было приостановлено.
• Поток может исполняться только при условии,
что значение счетчика приостановок равно
нулю.

И.В. Птицына & Б.Ф. Мишнев 63


Функция приостановки потоков
• Исполнение каждого потока может быть
приостановлено вызовом функции
suspendThread, которая имеет следующий
прототип:
DWORD SuspendThread( HANDLE hThread //
дескриптор потока );
• Эта функция увеличивает значение счетчика
приостановок на 1 и, при успешном
завершении, возвращает текущее значение этого
счетчика.

И.В. Птицына & Б.Ф. Мишнев 64


Возобновление потока
• Для возобновления исполнения потока
используется функция ResumeThread, которая
имеет следующий прототип:
DWORD ResumeThread( HANDLE hThread //
дескриптор потока
• Функция ResumeThread уменьшает значение
счетчика приостановок на 1 при условии, что это
значение было больше нуля.

И.В. Птицына & Б.Ф. Мишнев 65


Задержка выполнения
• Поток может задержать свое исполнение
вызовом функции Sleep, которая имеет
следующий прототип:
VOID Sleep( DWORD dwMiHiseconds //
миллисекунды );
• Единственный параметр функции Sleep
определяет количество миллисекунд, на
которые поток, вызвавший эту функцию,
приостанавливает свое исполнение.

И.В. Птицына & Б.Ф. Мишнев 66


67
Ожидание завершения потока
• DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds)

• DWORD WaitForMultipleObject (
DWORD nCount,
CONST HANDLE *lpHandles,
BOOL fWaitAll,
DWORD dwMilliseconds);

• INFINITE
• WAIT_TIMEOUT
• WAIT_OBJECT_0
• WAIT_FAILED

И.В. Птицына & Б.Ф. Мишнев 67


68
Удаленные потоки
• Функция CreateRemoteThread создает поток,
который запускается в виртуальном адресном
пространстве другого процесса.
• Если функция завершается успешно, величина
возвращаемого значения - дескриптор нового
потока.
• Если функция завершается ошибкой, величина
возвращаемого значения - ПУСТО (NULL).

И.В. Птицына & Б.Ф. Мишнев 68


69
Функция CreateRemoteThread
• HANDLE CreateRemoteThread(HANDLE hProcess,                  
       // дескриптор процесса
LPSECURITY_ATTRIBUTES lpThreadAttributes,
// дескриптор защиты (SD)
SIZE_T dwStackSize,                      
// размер начального стека
LPTHREAD_START_ROUTINE lpStartAddress,   
// функция потока
LPVOID lpParameter, // аргументы потока
DWORD dwCreationFlags,                   
// параметры создания
LPDWORD lpThreadId // идентификатор потока); 

И.В. Птицына & Б.Ф. Мишнев 69


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

Ирина Птицына & Борис Мишнев 70


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

Windows
• подсистема вытесняющей диспетчеризации
• приоритеты
• Квант
• Относительная длина кванта
• Шаг уменьшения длины
• HKLM\SYSTEM\CurrentControlSet\Control\PriorityC
ontrol\Win32PrioritySeparation
• Снижение приоритета

Ирина Птицына & Борис Мишнев 71


72

Выделение процессорного времени потокам

Ирина Птицына & Борис Мишнев 72


Обслуживание потоков
• Операционные системы Windows распределяют
процессорное время между потоками в
соответствии с их приоритетами.
• По истечении кванта времени исполнение
текущего потока прерывается, его контекст
запоминается и процессорное время
передается потоку с высшим приоритетом.
• такое обслуживание потоков в Windows
называется вытесняющая многозадачность
(preempting multitasking).

Ирина Птицына & Борис Мишнев 73


Уровни приоритета
• Внутренне Windows использует 32 уровня приоритета,
от 0 до 31. Эти значения разбиваются на части
следующим образом:
Шестнадцать уровней реального времени (от 16
до 31);

Шестнадцать изменяющихся уровней (от 0 до


15), из которых уровень 0 за резервирован для
потока обнуления страниц.

И.В. Птицына & Б.Ф. Мишнев 74


Класс приоритета
• Приоритет процессов устанавливается при их создании
функцией CreateProcess, используя параметр
dwCreationFiags.

И.В. Птицына & Б.Ф. Мишнев 75


Флаги классов приоритетов потоков
1. IDLE_PRIORITY_CLASS — класс фоновых процессов;
2. BELOW_NORMAL_PRIORITY_CLASS — класс процессов
ниже нормальных;
3. NORMAL_PRIORITY_CLASS — класс нормальных
процессов;
4. ABOVE_NORMAL_PRIORITY_CLASS — класс процессов
выше нормальных;
5. HIGH_PRIORITY_CLASS — класс высокоприоритетных
процессов;
6. REAL_TIME_PRIORITY_CLASS — класс процессов
реального времени.

Ирина Птицына & Борис Мишнев 76


77
Значения классов приоритетов
• REALTIME_PRIORITY_CLASS = 24
• HIGH_PRIORITY_CLASS = 13
• ABOVE_NORMAL_PRIORITY_CLASS = 10
• NORMAL_PRIORITY_CLASS = 8
• BELOW_NORMAL_PRIORITY_CLASS = 6
• IDLE_PRIORITY_CLASS = 4

Ирина Птицына & Борис Мишнев 77


Базовый класс процесса
• Процесс по умолчанию наследует свой базовый
приоритет у того процесса, который его создал.
• Это поведение может быть заменено другим в
функции CreateProcess или путем использования
пусковой команды в окне командной строки.
• Приоритет процесса может быть также изменен
после создания процесса путем использования
функции SetPriorityClass или различных
инструментальных средств, предлагающих такую
функцию, например Диспетчера задач и Process
Explorer (щелчок правой кнопкой мыши на имени
процесса и выбор нового класса приоритета).

И.В. Птицына & Б.Ф. Мишнев 78


Функция GetPriorityClass
• Функция GetPriorityClass извлекает
значение класса приоритета для
заданного процесса. Это значение, вместе
со значением приоритета каждого потока
процесса, обуславливает основной
уровень приоритета каждого потока.

Ирина Птицына & Борис Мишнев 79


Функция GetPriorityClass
• Синтаксис
DWORD GetPriorityClass(HANDLE hProcess // деск
риптор процесса);

• Если функция завершается успешно, величина


возвращаемого значения - класс приоритета
заданного процесса.
• Если функция завершается с ошибкой, величина
возвращаемого значения - ноль.

Ирина Птицына & Борис Мишнев 80


Функция SetPriorityClass

• Функция SetPriorityClass устанавливает
класс приоритета для заданного
процесса.
• Это значение вместе со значением
приоритета каждого потока процесса
обуславливает базовый уровень
приоритета каждого потока.

Ирина Птицына & Борис Мишнев 81


Функция SetPriorityClass
•Синтаксис
BOOL SetPriorityClass(HANDLE hProcess,      
// дескриптор процесса
DWORD dwPriorityClass 
// значение класса приоритета
);
• Если функция завершается успешно, величина
возвращаемого значения - не ноль.
• Если функция завершается с ошибкой, величина
возвращаемого значения - ноль.

Ирина Птицына & Борис Мишнев 82


Программное управление 83

приоритетом

SetPriorityClass (HANDLE hProcess,


DWORD fdwPriority );
SetPriorityClass( GetCurrentProcess(),
IDLE_PRIORITY_CLASS);

Ирина Птицына & Борис Мишнев 83


84
Назначение приоритета при запуске

C:\>START /LOW CALC.EXE

/LOW – idle
/BELOWNORMAL
/NORMAL
/ABOVENORMAL
/HIGH
/REALTIME
Ирина Птицына & Борис Мишнев 84
• Например, можно снизить приоритет процесса,
который интенсивно использует центральный
процессор, чтобы он не мешал обычным
действиям системы.
• Изменение приоритета процесса изменяют
приоритеты потоков, повышая их или снижая, но
их относительные установки остаются
прежними.

И.В. Птицына & Б.Ф. Мишнев 85


• Как правило, пользовательские приложения и службы
запускаются с обычным базовым приоритетом (normal),
поэтому их исходный поток чаще всего выполняется с
уровнем приоритета 8.
• Но некоторые системные процессы Windows (например,
диспетчер сеансов, диспетчер управления службами и
процесс идентификации локальной безопасности) имеют
немного более высокий базовый приоритет, чем тот,
который используется по умолчанию для класса Normal
(8). Это более высокое значение по умолчанию
гарантирует, что все потоки в этих процессах будут
запускаться с более высоким приоритетом,
превышающим значение по умолчанию равное 8.

И.В. Птицына & Б.Ф. Мишнев 86


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

И.В. Птицына & Б.Ф. Мишнев 87


Функция SetThreadPriority

• Функция SetThreadPriority устанавливает
значение приоритета для заданного
потока.
• Это значение, вместе с классом
приоритета процесса потока,
обуславливает базовый уровень
приоритета потока.

Ирина Птицына & Борис Мишнев 88


Функция SetThreadPriority

• Синтаксис
BOOL SetThreadPriority(HANDLE hThread, 
// дескриптор потока
int nPriority   // уровень приоритета потока);

• Если функция завершается успешно, величина


возвращаемого значения - не ноль.
• Если функция завершается с ошибкой, величина
возвращаемого значения - ноль.

Ирина Птицына & Борис Мишнев 89


90
Относительный приоритет потока
• BOOL SetThreadPriority ( HANDLE hThread, int
nPriority )

• THREAD_PRIORITY_TIME_CRITICAL 15 или 31
• THREAD_PRIORITY_HIGHEST +2
• THREAD_PRIORITY_ABOVE_NORMAL +1
• THREAD_PRIORITY_NORMAL 0
• THREAD_PRIORITY_BELOW_NORMAL -1
• THREAD_PRIORITY_LOWEST -2
• THREAD_PRIORITY_IDLE 1 или 16

Ирина Птицына & Борис Мишнев 90


Замечание 1
• Используйте класс приоритета процесса,
чтобы различать между прикладными
программами те, которые являются
критическими по времени исполнения и
те, которые требуют нормальной или
ниже нормальной очередности
обслуживания.

Ирина Птицына & Борис Мишнев 91


Замечание 2
• Используйте значения приоритета
потока, чтобы различать относительные
приоритеты задач процесса. Например,
поток, который обрабатывает ввод данных
для окна, может иметь более высокий
уровень приоритета, чем поток, который
выполняет интенсивные вычисления для
CPU.

Ирина Птицына & Борис Мишнев 92


Замечание 3

• При управлении приоритетами, будьте очень


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

Ирина Птицына & Борис Мишнев 93


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

И.В. Птицына & Б.Ф. Мишнев 94


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

И.В. Птицына & Б.Ф. Мишнев 95


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

И.В. Птицына & Б.Ф. Мишнев 96


Длина кванта времени
• На клиентских версиях Windows потоки по умолчанию
выполняются в течение двух интервалов таймера (clock
intervals), а на серверных системах поумолчанию поток
выполняется в течение 12 интервалов таймера.
• Причина более продолжительного значения по
умолчанию на серверных системах заключается в
стремлении минимизировать контекстные
переключения. За счет более продолжительного кванта
времени серверные приложения, пробуждаемые в
результате клиентского запроса, имеют более высокий
шанс на завершение обработки запроса и возвращение в
состояние ожидания до окончания их кванта времени.

И.В. Птицына & Б.Ф. Мишнев 97


• Продолжительность интервала таймера варьируется в
зависимости от аппаратной платформы. Частота
прерываний таймера зависит от HAL, а не от ядра.
• Например, интервал таймера на большинстве
однопроцессорных систем x86 (они больше не
поддерживаются Windows и упоминаются здесь только
для примера) составляет около 10 миллисекунд,
• на большинстве мультипроцессорных системx86 и x64 он
составляет порядка 15 миллисекунд. Этот интервал
таймера хранится в переменной ядра
KeMaximumIncrement в виде сотен наносекунд.

И.В. Птицына & Б.Ф. Мишнев 98


99
Резюме 1
• WINDOWS – поддерживает потоки,
которые планируются независимо друг от
друга, но разделяют адресное
пространство и ресурсы одного и того же
процесса.

И.В. Птицына & Б.Ф. Мишнев 99


100
Резюме 2
• Потоки дают программисту возможность
упростить программу и использовать
параллелизм выполнения задач для
повышения производительности
приложения.

И.В. Птицына & Б.Ф. Мишнев 100


101
Резюме 3
• Потоки могут обеспечивать выигрыш в
производительности даже в
однопроцессорных системах.

И.В. Птицына & Б.Ф. Мишнев 101


102

СПАСИБО ЗА
ВНИМАНИЕ!бо за
внимание

И.В. Птицына & Б.Ф. Мишнев 102