Принципы работы с потоками в Windows. Распределение процессорного времени между потоками

Для Windows механизм распределения процессорного времени между потоками примерно следующий. Поток выполняет код и манипулирует данными в адресном пространстве своего процесса примерно 20 мкс. Далее Windows сохраняет значения регистров процессора в контексте потока и приостанавливает его выполнение. Система просматривает остальные объекты ядра «поток», подлежащие выполнению и выбирает один из них, загружает его контекст в регистры процессора, и все повторяется. Этот цикл операций – выбор потока, загрузка его контекста, выполнение и сохранение контекста – начинается с момента запуска системы и продолжается до её выключения. Windows потому и называется системой с вытесняющей многозадачностью, что в любой момент может приостановить любой поток и вместо него запустить другой. Однако этим механизмом можно управлять, хотя и очень ограниченно.

Функция потока. В первичном потоке функцией потока является main, wmain, WinMain или wWinMain. Если создать вторичный поток, в нем тоже будет входная функция примерно следующего вида:

DWORD WINAPI ThreadFunc(PVOID pvParam)

{

DWORD rtwResult = 0;

….

return(dwResult);

}

Функция потока может выполнять любые задачи. Рано или поздно она закончит свою работу и вернет управление. В этот момент поток остановится и память, отведенная под его стек, будет освобождена, а счетчик пользователей его объекта ядра «поток» уменьшится на 1. Когда счетчик обнулится, этот объект ядра будет разрушен. Но, как и объект ядра «процесс», он может жить гораздо дольше, чем сопоставленный с ним поток.

Создание потока. При вызове функции CreateProcessпоявляется на свет первичный поток процесса. Для создания дополнительных потоков, нужно вызывать из первичного потока функцию CreateThread:

HANDLE CreateThread(

PSECURITY_ATTRIBUTES psa,

DWORD cbStack,

PTHREAD_START_ROUTINE pfnStartAddr,

PVOID pvParam,

DWORD tdwCreate,

PDWORD pdwThreadID);

При каждом вызове этой функции система создает объект ядра «поток» Это не сам поток, а компактная структура данных, которая используется операционной системой для управления потоком и хранит статистическую информацию о потоке. Так что объект ядра «поток» – полный аналог объекта ядра «процесс».

Система выделяет память под стек потока из адресного пространства процесса. Новый поток выполняется в контексте того же процесса, что и родительский поток. Поэтому он получает доступ ко всем описателям объектов ядра, всей памяти и стекам всех потоков в процессе. За счет этого потоки в рамках одного процесса могут легко взаимодействовать друг с другом.

Параметр psa. Параметр psa является указателем на структуру SECURITY_ATTRIBUTES. Если необходимо, чтобы объекту ядра «поток» были присвоены атрибуты защиты по умолчанию, в этом параметре передаётся NULL. A чтобы дочерние процессы смогли наследовать описатель этого объекта, необходимо определить структуру SECURITY_ATTRIBUTES и инициализировать ее элемент hInheritHandle значением TRUE.

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

Параметры pfnStartAddr и pvParam. Параметр pfnStartAddr определяет адрес функции потока, с которой должен будет начять работу создаваемый поток, а параметр pvParam идентичен параметру рvРаrат функции потока. CreateTbread лишьпередает этот параметр по эстафете той функ ции, с которой начинается выполнение создаваемого потока. Таким образом, данный параметр позволяет передавать функции потока какое-либо инициализирующее зна чение. Оно может быть или просто числовым значением, или указателем на труктур у данных с дополнительной информацией.

Параметр fdwCreate. Этот параметр определяет дополнительные флаги, управляющие созданием потока. Он принимает одно из двух значений. 0 (исполнение потока начинается немедленно) или CREATE_SUSPENDED. В последнем случае система создает поток, инициализирует его и приостанавливает до последующих указаний. Флаг CREATE_SUSPENDED позволяет программе изменить какие-либо свойства потока перед тем, как он начнет выполнять код.

Параметр pdwThreadID. Последний параметр функции это адрес переменной типа DWORD, в которой функция возвращает идентификатор, приписанный системой новому потоку.