Программирование для Windows NT

       

Функция CreateThread


Прототип функции CreateThread, с помощью которой процессы могут создавать задачи, представлен ниже:

HANDLE CreateThread(

  LPSECURITY_ATTRIBUTES lpThreadAttributes,// атрибуты защиты

  DWORD dwStackSize,       // начальный размер стека в байтах

  LPTHREAD_START_ROUTINE lpStartAddress,// адрес функции

                                        // задачи

  LPVOID  lpParameter,           // параметры для задачи

  DWORD   dwCreationFlags,       // параметры создания задачи

  LPDWORD lpThreadId);           // адрес переменной для

                                 // идентификатора задачи

Через параметр lpThreadAttributes передается адрес структуры SECURITY_ATTRIBUTES, определяющей атрибуты защиты для создаваемой задачи, или значение NULL. В последнем случае для задачи будут использованы атрибуты защиты, принятые по умолчанию. Это означает, что идентификатор созданной задачи можно использовать в любых функциях, выполняющих любые операции над задачами. Указывая атрибуты защиты, вы можете запретить использование тех или иных функций.

Приведем структуру SECURITY_ATTRIBUTES:

typedef struct _SECURITY_ATTRIBUTES 



{

  DWORD  nLength;              // размер структуры в байтах

  LPVOID lpSecurityDescriptor; // указатель на дескриптор

                               //   защиты

  BOOL   bInheritHandle;       // флаг наследования

                               //   идентификатора

} SECURITY_ATTRIBUTES;

При подготовке структуры в поле nLength следует записать размер структуры SECURITY_ATTRIBUTES.

Поле указателя на дескриптор защиты lpSecurityDescriptor не заполняется приложением непосредственно. Вместо этого для установки дескритора защиты используется набор функций, которым в качестве одного из параметров передается указатель на структуру SECURITY_ATTRIBUTES. Эти функции подробно описаны в SDK. В нашей книге для экономии места мы не будем на них останавливаться. Система защиты Microsoft Windows NT достаточно мощная и потому заслуживает отдельного рассмотрения.

Параметр dwStackSize функции CreateThread позволяет указать начальный размер стека для запускаемой задачи. Если указать для этого параметра нулевое значение, размер стека запущенной задачи будет равен размеру стека главной задачи процесса. При необходимости размер стека автоматически увеличивается.


Таким образом, первые два параметра функции CreateThread не вызывают затруднений. Они могут быть в большинстве случаев указаны как NULL и 0, соответственно.

Параметр lpStartAddress задает адрес функции, которая будет выполняться как отдельная задача. Здесь вы можете просто указать имя этой функции. Функция задачи имеет один 32-разрядный параметр и возвращает 32-разрядное значение. Указанный параметр передается функции CreateThread через параметр lpParameter.

Если значение параметра dwCreationFlags равно нулю, после вызова функции CreateThread задача немедленно начнет свое выполнение. Если же в этом параметре указать значение CREATE_SUSPENDED, задача будет загружена, но приостановлена. Возобновить выполнение приостановленной задачи можно будет позже с помощью функции ResumeThread.

И, наконец, через параметр lpThreadId вы должны передать адрес переменной типа DWORD, в которую бедет записан системный номер созданной задачи (thread identifier).

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

Ниже мы приведи пример использования функции CreateThread:

hThread = CreateThread(NULL, 0,

  (LPTHREAD_START_ROUTINE)ThreadRoutine,

  (LPVOID)hwndChild, 0,(LPDWORD)&dwIDThread);

Здесь мы не используем атрибуты защиты и устанавливаем размер стека запускаемой задачи, равным размеру стека главной задачи процесса.

В качестве функции задачи мы использовали функцию с именем ThreadRoutine, имеющую следующий вид:

DWORD ThreadRoutine(HWND hwnd)

{

  . . .

  // Оператор return завершает выполнение задачи

  return 0;

}

Эта функция имеет один параметр, который в нашем случае будет принимать значение hwndChild.

Наша функция задачи завершает свое выполнение оператором return, хотя, как вы увидите дальше, есть и другие способы. Для проверки значения, возвращенного функцией задачи, процесс может воспользоваться функцией GetExitCodeThread, которая будет описана позже.

Так как при запуске задачи мы указали значение параметра dwCreationFlags, равное нулю, сразу после запуска задача начнет свою работу. Системный номер созданной задачи будет записан в переменную dwIDThread.


Содержание раздела