|
Создается поток функцией CreateThread, которая имеет следующий прототип:
HANDLE CreateThread {
LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибуты зашиты
DWORD dwStackSize, // размер стека потока в байтах
LPTHREAD_START_ROUTINE lpStartAddress, // адрес функции
LPVOID lpParameter, // адрес параметра
DWORD dwCreationFlags, // флаги создания потока
LPDWORD lpThreadId // идентификатор потока
};
При успешном завершении функция CreateThread возвращает дескриптор созданного потока и его идентификатор, который является уникальным для всей системы. В противном случае эта функция возвращает значение NULL. Кратко опишем назначение параметров функции CreateThread.
Параметр lpThreadAttributes устанавливает атрибуты зашиты создаваемого потока. До тех пор пока мы не изучим систему безопасности в Windows, мы будем устанавливать значения этого параметра в NULL при вызове почти всех функций ядра Windows. В данном случае это означает, что операционная система сама установит атрибуты зашиты потока, используя настройки по умолчанию. О процессах будет подробно рассказано в следующей главе.
Параметр dwStackSize определяет размер стека, который выделяется потоку при запуске. Если этот параметр равен нулю, то потоку выделяется стек, размер которого по умолчанию равен 1 Мбайт. Это наименьший размер стека, который может быть выделен потоку. Если величина параметра dwStackSize меньше значения, заданного по умолчанию, то все равно потоку выделяется стек размером в 1 Мбайт. Операционная система Windows округляет размер стека до одной страницы памяти, который обычно равен 4 Кбайт.
Параметр lpStartAddress указывает на исполняемую потоком функцию. Эта функция должна иметь следующий прототип:
DWORD WINAPI имя_функции_потока(LPVOID IpParameters);
Видно, что функции потока может быть передан единственный параметр lpParameter, который является указателем на пустой тип. Это ограничение следует из того, что функция потока вызывается операционной системой, а не прикладной программой. Программы операционной системы являются исполняемыми модулями и поэтому они должны вызывать только функции, сигнатура которых заранее определена. Поэтому для потоков определили самый простой список параметров, который содержит только указатель. Так как функции потоков вызываются операционной системой, то они также получили название функции обратного вызова.
Параметр dwCreationFlags определяет, в каком состоянии будет создан поток. Если значение этого параметра равно 0, то функция потока начинает выполняться сразу после создания потока. Если же значение этого параметра равно create_suspended, то поток создается в подвешенном состоянии. В дальнейшем этот поток можно запустить вызовом функции ResumeThread.
Параметр lpThreadid является выходным, т. е. его значение устанавливает Windows. Этот параметр должен указывать на переменную, в которую Windows поместит идентификатор потока. Этот идентификатор уникален для всей системы и может в дальнейшем использоваться для ссылок на поток. Идентификатор потока главным образом используется системными функциями и редко функциями приложения. Действителен идентификатор потока только на время существования потока. После завершения потока тот же идентификатор может быть присвоен другому потоку. В операционной системе Windows 98 этот параметр не может быть равен null. В Windows NT и 2000 допускается установить его значение в null — тогда операционная система не возвратит идентификатор потока.
В листинге 3.1 приведен пример программы, которая использует функцию CreateThread для создания потока, и демонстрирует способ передачи параметров исполняемой потоком функции.
Листинг 3.1. Создание потока функцией CreateThread |
|
|
#include <windows.h>
#include <iostream.h>
volatile int n;
DWORD WINAPI Add(LPVOID iNum)
{
cout << "Thread is started." << endl;
n += (int)iNum;
cout << "Thread is finished." << endl;
return 0;
}
int main()
{
int inc = 10;
HANDLE hThread;
DWORD IDThread;
cout << "n = " << n << endl;
// запускаем поток Add
hThread = CreateThread(NULL, 0, Add, (void*)inc, 0, &IDThread);
if (hThread == NULL)
return GetLastError();
// ждем, пока поток Add закончит работу
WaitForSingleObject(hThread, INFINITE);
// закрываем дескриптор потока Add
CloseHandle(hThread);
cout << "n = " << n << endl;
return 0;
} |
|