Многопоточность в Windows
Цель работы: изучить функции и структуры данных Windows API, используемые для управления потоками, исследовать базовые механизмы взаимодействия потоков, ознакомиться с принципами управления приоритетами потоков.
3.1. Общие сведения
Понятие потока выполнения. Назначение потоков. Приложение в системе Microsoft Windows состоит из одного и более процессов. ОС Windows распределяет все ресурсы, необходимые для выполнения программ, за исключением процессорного времени, между процессами. Каждый процесс имеет свое собственное адресное пространство, пользовательский контекст и системный контекст (например, таблицу объектов ядра), базовый приоритет, переменные окружения и т.п. Каждый процесс включает хотя бы один поток исполнения (thread of execution) – стартовый, но по мере необходимости могут создаваться и дополнительные потоки. Именно между потоками и распределяется процессорное время. Таким образом, потоки разделяют адресное пространство и системные ресурсы процесса. Кроме того, каждый поток имеет свой собственный приоритет, регистровый контекст и часть системного контекста – стек ядра, стек пользователя ипеременные окружения.
Многопоточные приложения используются в следующих случаях:
–для управления вводом от нескольких окон;
–для управления вводом от нескольких периферийных устройств или средств взаимодействия;
–для эффективного и гибкого использования системы приоритетов;
–для повышения интерактивности взаимодействия приложения и пользователя;
–для обработки данных в «фоновом» режиме.
Использование одного многопоточного процесса зачастую эффективнее, чем применение многопроцессной реализации по следующим причинам:
–переключение контекста между потоками происходит быстрее, чем между процессами, так как контекст процесса «больше», чем контекст потока;
–потоки разделяют адресное пространство процесса и могут иметь одновременный доступ к глобальным переменным процесса, что упрощает взаимодействие потоков;
потоки могут совместно использовать таблицу дескрипторов объектов ядра (например, файлов, каналов и т.п.).
Для создания потока (базовый поток создается при создании
процесса) используется системный вызов CreateThread (для создания потока в контексте другого процесса используетсяCreateRemoteThread). Объявление потока производится аналогично объявлению функции или процедуры, причем объявляемая функция может содержать формальный параметр – нетипизированный указатель, который может быть соответствующим образом разыменован и использован при реализации потока. Объявление функциипотока должно обязательно сопровождаться модификаторомWINAPI, который скрывает за собой модификатор__stdcall (строго говоря, то что скрывается за макроопределениемWINAPI зависит от аппаратной платформы и версии операционной системы).
Пример объявления функции-потока:
DWORD WINAPI ThreadFunc(LPVOID lpParam) { printf("ThreadFunc: Parameter = %d\n",
*(int*)lpParam ); getch();
return 0;
}
Согласование взаимодействия потоков может осуществляться с помощью функций вида «WaitFor…». Механизм согласования (синхронизации) в этом случае основан на том, что объекты синхронизации – как специализированные (события, мьютексы и т.п.), так и неспециализированные (файлы, процессы, потоки) – могут находиться в сигнальном и несигнальном состояниях. В частности, считается, что поток находиться в несигнальном состоянии, если он выполняется, и поток переходит в сигнальное состояние в тот момент, когда он завершается. Например, если необходимо в течении 2 секунд ожидать завершения потока, дескриптор которогоhThread, то можно использовать следующую конструкцию:
WaitForSingleObject(hThread, 2000);
Выполнение потока, в котором будет использована эта конструкция, приостановится и продолжиться тогда, когда либо поток перейдет в сигнальное состояние (т.е. завершится), либо истечет указанный интервал времени (2000 мс).
Windows API предоставляет набор функций, позволяющих управлять приоритетами потоков:
–GetThreadPriority – возвращает значение приоритета потока;
–SetThreadPriority – назначает значение приоритета потока;
- GetProcessPriorityBoost – позволяет узнать, допускается ли динамическое изменение приоритета потока;
–SetProcessPriorityBoost – включает или отключает режим динамического изменения приоритета потока.
Как и для работы с процессами, существуют аналогичные функции, управляющие потоками, например GetThreadTimes, TerminateThread и т.п.
При выполнении работы следует обратить внимание на аппаратное обеспечение вычислительной системы. При необходимости можно «заставить» потоки выполняться на одном ядре (процессоре)
используя функцию SetThreadAffinityMask илиSetProcessAffinityMask.