0, // Флажки создания
NULL, // использование конфигурации родителя
NULL, // использование текущего каталога родителя
&siStartInfo, // указатель на STARTUPINFO
&piProcInfo); // принимаем PROCESS_INFORMATION
Создание потоков
Функция CreateThread создает для процесса новый поток. Созданный поток должен определить начальный адрес кода, с которого новый поток должен исполняться. Как правило, начальный адрес - это название функции, определенной в коде программы. Эта функция получает единственный параметр и возвращает значение типа DWORD. Процесс может иметь одновременно несколько потоков, выполняющих ту же самую функцию.
Нижеследующий пример демонстрирует, как создать новый поток, который выполняет локально определяемую функцию ThreadFunc.
|
#include <windows.h> #include <conio.h> DWORD WINAPI ThreadFunc(LPVOID lpParam) { char szMsg[80]; wsprintf(szMsg, "Parameter = %d", *(DWORD*)lpParam); MessageBox( NULL, szMsg, " ThreadFunc", MB_OK ); return 0; } VOID main( VOID ) { DWORD dwThreadId, dwThrdParam = 1; HANDLE hThread; char szMsg[80]; hThread = CreateThread( NULL, // атрибуты безопасности по умолчанию 0, // размер стека используется по умолчанию ThreadFunc, // функция потока &dwThrdParam, // аргумент функции потока 0, // флажки создания используются по умолчанию &dwThreadId); // возвращает идентификатор потока // При успешном завершении проверяет возвращаемое значение. if (hThread == NULL) { wsprintf( szMsg, "CreateThread failed." ); MessageBox( NULL, szMsg, "main", MB_OK ); } else { _getch(); CloseHandle( hThread ); } } |
Для простоты, этот пример передает указатель на значение как на параметр функции потока. Это может быть указатель на любой тип данных или структуру, или это может быть пропущено совсем, при помощи передачи указателя NULL и удаления ссылок на параметр в ThreadFunc.
Приостановка исполнения потока
Поток может приостанавливать работу и восстанавливать исполнение другого потока, используя функции SuspendThread и ResumeThread. В то время когда поток приостановлен, он в течение этого периода не допускается к работе на процессоре.
Функция SuspendThread не особенно полезна для синхронизации, потому что она не управляет точкой в коде, в которой было приостановлено выполнение потока. Однако у Вас может возникнуть желание приостановить работу потока в ситуации, когда ожидается ввод данных от пользователя, который может отменить работу выполняемого потока. Если пользователь вводит данные, отменяющие работу, поток исчезает; иначе, вызывается ResumeThread.
Завершение работы потока
Поток исполняется до тех пор, пока не произойдет одно из нижеследующих событий:
-
Поток вызывает функцию ExitThread.
-
Какой-либо поток процесса вызывает функцию ExitProcess.
-
Какой-либо поток вызывает функцию TerminateThread с дескриптором потока.
-
Какой-либо поток вызывает функцию TerminateProcess
Создание процессов
Функция CreateProcess создает новый процесс, который запускается независимо от процесса, который его создал. Однако для простоты, это взаимоотношение упоминается как родительское - дочернее отношение.
Нижеследующий фрагмент кода показывает, как создать процесс.
|
void main( VOID ) { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); // Запустим дочерний процесс. if( !CreateProcess( NULL, // Нет имени модуля (используется командная строка). "MyChildProcess", // Командная строка. NULL, // Дескриптор процесса не наследуемый. NULL, // Дескриптор потока не наследуемый. FALSE, // Установим наследование дескриптора в FALSE. 0, // Флажков создания нет. NULL, // Используйте блок конфигурации родителя. NULL, // Используйте стартовый каталог родителя. &si, // Указатель на структуру STARTUPINFO. &pi ) // Указатель на структуру PROCESS_INFORMATION. ) ErrorExit( "CreateProcess failed." ); // Ждать до тех пор, пока дочерний процесс не выйдет из работы. WaitForSingleObject( pi.hProcess, INFINITE ); // Закроем дескрипторы процесса и потока. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); } |
Если CreateProcess завершается успешно, она возвращает структуру PROCESS_INFORMATION, содержащую дескрипторы и идентификаторы для нового процесса и первичного потока. Дескрипторы потока и процесса создаются с полными правами доступа, хотя доступ может быть ограничен, если Вы устанавливаете описатели системы безопасности. Когда Вы больше не нуждаетесь в этих дескрипторах, то закрываете их при помощи использования функции CloseHandle.
Функция CloseHandle
Функция CloseHandle закрывает открытый дескриптор объекта.
Синтаксис
|
BOOL CloseHandle( HANDLE hObject // дескриптор объекта ); |
Параметры
hObject [in/out] Дескриптор открытого объекта.
Возвращаемые значения
Если функция завершается успешно, величина возвращаемого значения - не ноль.
Если функция завершается с ошибкой, величина возвращаемого значения - ноль.
STARTUPINFO
Структура STARTUPINFO используется функцией CreateProcess для определения свойств главного окна, если новое окно создаётся для нового процесса. Для процессов графического интерфейса пользователя (GUI), эта информация относится к первому окну, создаваемому функцией CreateProcess и показываемому функцией ShowWindow. Для консольных приложений эта информация относится к консольному окну, если таковое создаётся.
Завершение работы процесса
Процесс выполняется до тех пор, пока не произойдет одно из нижеследующих событий:
-
Какой-либо поток процесса вызывает функцию ExitProcess. Она завершает работу всех потоков процесса.
-
Первичный поток процесса возвращает значение. Первичный поток может отменить завершение работы других потоков, при помощи явного вызова ExitThread перед возвратом своего значения. Один из оставшихся потоков может все еще вызвать ExitProcess, чтобы гарантировать, что все потоки завершили работу.
-
Последний поток процесса завершил работу.
-
Какой-либо поток вызывает функцию TerminateProcess с дескриптором процесса. Это завершает работу всех потоков процесса, без разрешения им, чтобы они очистили или сохранили данные.
Когда процесс завершает работу, все потоки процесса немедленно завершают работу без шанса запустить дополнительный код. Это означает то, что процесс не выполняет код в блоках обработчика завершения работы.
ZeroMemory - Функция ZeroMemory заполняет указанный фрагмент памяти нулями
procedure ZeroMemory( Destination: Pointer; // блок памяти Length: DWORD); // длина блока памяти
Параметры
Destination [out] - Указатель на начало блока, который будет обнулен.
Length [in] - Указывает длину в байтах блока, который будет обнулен.
PROCESS_INFORMATION
Структура PROCESS_INFORMATION заполняется функцией CreateProcess информацией о новом созданном процессе и его главном потоке.
typedef struct _PROCESS_INFORMATION { // pi HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION;
hProcess - Возвращает дескриптор нового процесса. Этот дескриптор используется для указания процесса во всех функциях оперирующих с объектом процесса.
hThread - Возвращает дескриптор на главный поток нового процесса. Этот дескриптор используется для указания потока во всех функциях оперирующих с объектом потока.
dwProcessId - Возвращает глобальный процессный идентификатор, используемый для распознания процесса. Это значение действительно с того времени как создан процесс до его уничтожения.
dwThreadId - Возвращает глобальный поточный идентификатор, используемый для распознания потока. Это значение действительно с того времени как создан поток до его уничтожения.
Wait-функции позволяют потоку в любой момент приостановиться и ждать освобож дения какого-либо объекта ядра. Из всего семейства этих функций чаще всего исполь зуется WaitForSingleObject:
DWORD WaitForSingleObject( HANDLE hObject, DWORD dwMilliseconds);
Когда поток вызывает эту функцию, первый параметр, hObject, идентифицирует объект ядра, поддерживающий состояния «свободен-занят» (То есть любой объект, упомянутый в списке из предыдущего раздела.) Второй параметр, dwMilliseconds, ука зывает, сколько времени (в миллисекундах) поток готов ждать освобождения объекта.
Следующий вызов сообщает системе, что поток будет ждать до тех пор, пока не завершится процесс, идентифицируемый описателем hProcess.
WaitForSingleObject(hProcess, INFINITE);
В данном случае константа INFINITE, передаваемая во втором параметре, подска зывает системе, что вызывающий поток готов ждать этого события хоть целую веч ность. Именно эта коистанта обычно и передается функции WaitForSingleObject, но Вы можете указать любое значение в миллисекундах. Кстати, константа INFINITE опре делена как 0xFFFFFFFF (или -1). Разумеется, передача INFINlTE нс всегда безопасна Если объект так и не перейдет в свободное состояние, вызывающий поток никогда не проснется; одно утешение, тратить драгоценное процессорное время он при этом не будет
Вот пример, иллюстрирующий, как вызывать WaitForSingleObject co значением тай маута, отличным от INFINITE
DWORD dw = WaitForSlngleObject(hProcess, 5000);
switch (dw) { case WAIT_OBJECT_0: // процесс завершается break;
case WAIT_TIMEOUT: // процесс не завершился в течение 5000 мс break;
case WAIT_FAILED: // неправильный вызов функции (неверный описатель?) break; }
Данный код сообщает системе, что вызывающий поток не должен получать про цессорное время, пока не завершится указанный процесс или не пройдет 5000 мс (в зависимости от того, что случится раньше). Поэтому функция вернет управление либо до истечения 5000 мс, если процесс завершится, либо примерно через 5000 мс, если процесс к тому времени не закончит свою работу Заметьте, что в параметре dwMilli seconds можно передать 0, и гогда WaitForSingleObject немедленно вернет управление
Возвращаемое значение функции WaitForSingleObject указывает, почему вызываю щий поток снова стал планируемым Если функция возвращает WAITOBTECT_0, объ ект свободен, а если WAIT_TIMEOUT — заданное время ожидания (таймаут) истекло. При передаче неверного параметра (например, недопустимого описателя) WaitForSing leObject возвращает WAIT_ EAILED. Чтобы выяснить конкретную причину ошибки, вы зовите функцию GetLastErroY.
