Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
sp.docx
Скачиваний:
1
Добавлен:
01.03.2025
Размер:
213.38 Кб
Скачать

24. Потоки и многопоточные приложения. Порождение потоков, состояние потоков, управление ими. Основы управления потоками Win32

Поток Win 32 – базовый объект планирования выполнения задач и распределения процессорного времени. Каждый процесс имеет первоначально один первичный (главный, primary) поток и может затем создавать произвольное (ограниченное доступными ресурсами) количество вторичных потоков. Потоки одного процесса, равно как и потоки различных процессов, выполняются одновременно, асинхронно и независимо друг от друга.

Переключение потоков осуществляется планировщиком задач прозрачно для самих потоков. Текущее состояние потока описывается его контекстом исполнения, куда входят регистры процессора, переменные окружения, стеки ядра и пользователя. Заполнение структуры контекста происходит в те моменты, когда планировщик "отбирает" управление у потока. Продолжительность распределяемого потоку кванта времени в различных ОС семей­ства Win 32 составляет 10..20 мс, но величина эта недостаточно стабильна, и ориентиро­ваться на нее, например, при измерении интервалов времени, проблематично. Уменьшение кванта повышает оперативность реагирования системы на события, но увеличивает непроиз­водительные затраты на переключение потоков.

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

С точки зрения программиста поток описывается как вполне "нормальная" функция, однако вызов ее осуществляется не явно, а путем передачи ее адреса в функцию Create­Thread. После этого функция начинает выполняться в новом отдельном потоке, и все ее действия, включая вызовы других функций, остаются в рамках этого потока. Поток завер­шается завершением его функции.

Еще один случай неявного "вхождения" в поток – вызов обработчика сообщения, который активизируется и исполняется в том же потоке, в котором данное сообщение было выбрано и перенаправлено на исполнение (см. цикл обработки сообщений).

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

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

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttrib, //атрибутызащитыпотока

DWORD dwStackSize, //размерстекапотока

LPTHREAD_START_ROUTINE lpStartAddr, //адресфункциипотока

LPVOID lpParam, //параметрфункциипотока

DWORD dwCreationFlags, //флагисозданияпотока

LPDWORD lpThreadId //указатель переменной – идентификатора созданного потока

)

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

Типу LPTHREAD_START_ROUTINE соответствует следующий формат функции:

DWORD WINAPI ThreadRoutineName(LPVOID lpParam).

Наличие передаваемого параметра и возвращаемого значения обязательны, но их интерпретация в программе произвольна (целое значение, указатель, игнорирование).

В качестве флагов создания потока может быть задано значение CREATE_SUSPENDED – создавать поток в приостановленном состоянии.

Доступ к потоку может быть получен функцией OpenThread(), формат которой подобен OpenProcess():

HANDLE OpenThread(

DWORD dwDesiredAccess, // запрашиваемые права доступа

BOOLbInheritHandle, // флаг разрешения наследования описателя

DWORDdwThreadId // идентификатор "заказанного" потока

)

Сам поток может получить свои идентификатор и описатель с помощью функций GetCurrentThreadId() и GetCurrentThread() соответственно.

Для управления состоянием созданного потока служат следующие функции:

ResumeThread(HANDLEhThread) – активизация или возобновление выполнения потока;

SuspendThread(HANDLEhThread) – приостановка выполнения потока.

В действительности функции управляют лишь флагом приостановки потока, который представляет собой целое неотрицательное значение: SuspendThread() увеличивает его на единицу, а ResumeThread() уменьшает, но не ниже 0. Пока значение флага больше нуля, поток остается приостановленным. Очевидно, многократные "приостановки" потока требуют такого же количества его "запусков". Обе функции возвращают предыдущее значение флага, что позволяет ориентироваться в случаях, когда оно заранее не известно.

Корректное завершение потока "изнутри" осуществляется вызовом

voidExitThread(DWORDdwExitCode).

Единственный параметр – код возврата, который подобен коду возврата процесса и может быть затем получен "извне" вызовом

BOOLGetExitCodeThread(

HANDLEhThread, // описатель завершившегося потока

LPDWORDlpdwExitCode // указатель на переменную, которой передается значение

)

Для принудительного "жесткого" завершения потока "извне" служит функция

BOOL TerminateThread(

HANDLE hThread, //описательпотока

DWORD dwExitCode //его будущий код возврата

)

Замечания относительно принудительного завершения потока те же, что и в отношении процесса.

Завершение первичного потока процесса вызывает завершение процесса в целом. Завершение процесса сопровождается завершением всех его потоков.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]