Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows


Параметры pfnStartAddr и pvParam


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

Вполне допустимо и даже полезно создавать несколько потоков, у которых в ка честве входной точки используется адрес одной и той же функции. Например, мож но реализовать Web-сервер, который обрабатывает каждый клиентский запрос в от дельном потоке. При создании каждому потоку передается свое значение рvParam.

Учтите, что Windows — операционная система с вытесняющей многозадачностью, а следовательно, новый поток и поток, вызвавший CreateThread, могут выполняться одновременно В связи с этим возможны проблемы Остерегайтесь, например, такого кода.

DWORD WINAPI FirstThread(PVOID pvParam)
{
// инициализируем переменную, которая содержится в стеке

int x = 0;
DWORD dwThreadID;

// создаем новый поток
HANDLE hThread = CreateThread(NULL, 0, SecondThread, (PVOID) &x, 0, &dwThreadId);

// мы больше не слылаемся на новый поток,
// поэтому закрываем свой описатель этого потока
CloseHandle(hThread);

// Наш поток закончил работу.
// ОШИБКА, его стек будет разрушен, но SecondThread // может попытаться обратиться к нему return(0);
}

DWORD WINAPI SecondThread(PVOID pvParam) {
// здесь выполняется какая-то длительная обработка
// Пытаемся обратиться к переменной в стеке FirstThread,
// ПРИМЕЧАНИЕ- это может привести к ошибке общей защиты
// нарушению доступа * ((int *) pvParam) = 5;

relurn(0);
}

Не исключено, что в приведенном коде FirstThread закончит свою работу до того, как SecondThread присвоит значение 5 переменной x из FirstThread. Если так и будет, SecondThread не узнает, что FirstThread больше не существует, и попытается изменить содержимое какого-то участка памяти с недействительным теперь адресом. Это не избежно вызовет нарушение доступа: стек первого потока уничтожен по завершении

FirstThread. Что же делать? Можно объявить x статической переменной, и компиля тор отведет память для хранения переменной x не в стеке, а в разделе данных прило жения (application's data section). Ho тогда функция станет нереентерабельной. Ина че говоря, в этом случае Вы не смогли бы создачь два потока, выполняющих одну и ту же функцию, так как оба потока совместно использовали бы статическую перемен ную Другое решение этой проблемы (и его более сложные варианты) базируется па методах синхронизации потоков, речь о которых поЙдет в главах 8, 9 и 10.




Начало  Назад  Вперед