Для 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, в которой функция возвращает идентификатор, приписанный системой новому потоку.