- •Процессы, нити и волокна
- •CrProces.C
- •Int apientry WinMain( hinstance hInstance, hinstance hPrevInstance,
- •Объекты синхронизации
- •Защита процесса от нереентрабельного кода
- •Описание функций управления процессами, нитями и волокнами
- •CreateEvent
- •CrEvent.C
- •Int apientry WinMain( hinstance hInstance, hinstance hPrevInstance,
- •CreateMutex
- •CrMutex.C
- •Int apientry WinMain( hinstance hInstance, hinstance hPrevInstance,
- •CreateSemaphore
- •CrSem.C
- •Int apientry WinMain( hinstance hInstance, hinstance hPrevInstance,
- •CreateThread
- •EnterCriticalSection
- •EntCrSec.C
- •Int apientry WinMain( hinstance hInstance, hinstance hPrevInstance,
- •ExitThread
- •InitializeCriticalSection
- •DeleteCriticalSection
- •LeaveCriticalSection
- •OpenSemaphore
- •TryEnterCriticalSection
- •WaitForMultipleObjects
Процессы, нити и волокна
В Windows NT/2000 и Windows 9.x поддерживаются мультинитевые процессы. Процесс (process) представляет собой объект, которому принадлежат ресурсы приложения. А нить (thread) – это независимый путь выполнения внутри процесса, разделяющий вместе с процессом общее адресное пространство, код и глобальные данные. У каждой нити имеются собственные регистры, стек и механизмы ввода, в том числе и очередь скрытых сообщений. В Windows NT/2000 и Windows 9.x временные интервалы выделяются на основе нитей, а вытесняющая многозадачность реализуется на базе приоритетов, назначаемых для каждой нити. Кроме того, в Windows NT/2000 имеется возможность использовать несколько процессоров для обслуживания нитей процесса. Чем больше процессоров, тем больше временных интервалов имеется для нитей. Благодаря такой возможности, процессы, которые выполняются на машине с двумя и более процессоров, работающей под управлением Windows NT/2000, в принципе могут выполняться быстрее, чем в случае, если бы они выполнялись под управлением Windows 9.x.
Создание процессов и нитей
Функция CreateProcess создает объект процесса, а также объект основной нити приложения. Функция CreateProcess дает также родительскому процессу возможность устанавливать рабочую среду для нового процесса, в том числе и новый рабочий каталог, способ отображения этого процесса на экране, его переменные окружения, приоритет и передаваемую ему командную строку. Выполнение нового процесса начнется с адреса его запуска и будет продолжено вплоть до его завершения.
Листинг 1. Применение функции CreateProcess для выполнения программы
CrProces.h
#define IDM_EXIT 100
#define IDM_TEST 200
#define IDM_ABOUT 301
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About (HWND, UINT, WPARAM, LPARAM);
CrProces.rc
#include "windows.h"
#include "CrProces.h"
MYAPP ICON DISCARDABLE "GENERIC.ICO"
MYAPP MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", IDM_EXIT
END
MENUITEM "&Test!", IDM_TEST
POPUP "&Help"
BEGIN
MENUITEM "&About My Application...", IDM_ABOUT
END
END
ABOUTBOX DIALOG 22, 17, 171, 43
STYLE DS_MODALFRAME | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU
CAPTION "My Application"
FONT 8, "MS Sans Serif"
{
CONTROL "MyApp", -1, "STATIC", SS_ICON | WS_CHILD | WS_VISIBLE, 3, 2, 16, 16
CONTROL "Generic Application", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 28, 4, 100, 8
CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 116, 26, 50, 14
}
CrProces.C
#include <windows.h>
#include "CrProces.h"
HINSTANCE hInst; // current instance
LPCTSTR lpszAppName = "MyApp";
LPCTSTR lpszTitle = "My Application";
Int apientry WinMain( hinstance hInstance, hinstance hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASSEX wc;
// Register the main application window class.
//............................................
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, lpszAppName );
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = lpszAppName;
wc.lpszClassName = lpszAppName;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIconSm = LoadImage( hInstance, lpszAppName,
IMAGE_ICON, 16, 16,
LR_DEFAULTCOLOR );
if ( !RegisterClassEx( &wc ) )
return( FALSE );
hInst = hInstance;
// Create the main application window.
//....................................
hWnd = CreateWindow( lpszAppName,
lpszTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
NULL,
NULL,
hInstance,
NULL
);
if ( !hWnd )
return( FALSE );
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
while( GetMessage( &msg, NULL, 0, 0) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return( msg.wParam );
}
HWND hList = NULL;
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_CREATE :
// Create list box.
//.................
hList = CreateWindowEx( WS_EX_CLIENTEDGE, "LISTBOX", "",
LBS_STANDARD | LBS_NOINTEGRALHEIGHT |
WS_CHILD | WS_VISIBLE,
0, 0, 10, 10,
hWnd, (HMENU)101,
hInst, NULL );
break;
case WM_SIZE :
if ( wParam != SIZE_MINIMIZED )
MoveWindow( hList, 0, 0, LOWORD( lParam ), HIWORD( lParam ), TRUE );
break;
case WM_COMMAND :
switch( LOWORD( wParam ) )
{
case IDM_TEST:
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
// Initialize structures.
//.......................
ZeroMemory( &si, sizeof(STARTUPINFO) );
ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
si.cb = sizeof( STARTUPINFO );
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
CreateProcess( NULL, "CALC", NULL, NULL, FALSE,
0, NULL, NULL, &si, &pi );
WaitForInputIdle( GetCurrentProcess(), INFINITE );
// Loop until process terminates.
//...............................
if ( pi.hProcess )
{
DWORD dwExitCode = STILL_ACTIVE;
while ( dwExitCode == STILL_ACTIVE )
{
WaitForSingleObject( pi.hProcess, 1000 );
GetExitCodeProcess( pi.hProcess, &dwExitCode );
SendMessage( hList, LB_INSERTSTRING, 0, (LPARAM)"Waiting for Calc." );
UpdateWindow( hWnd );
}
SendMessage( hList, LB_INSERTSTRING, 0, (LPARAM)"Calc is Finished" );
}
}
break;
case IDM_ABOUT :
DialogBox( hInst, "AboutBox", hWnd, (DLGPROC)About );
break;
case IDM_EXIT :
DestroyWindow( hWnd );
break;
}
break;
case WM_DESTROY :
PostQuitMessage(0);
break;
default :
return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}
return( 0L );
}
LRESULT CALLBACK About( HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return (TRUE);
case WM_COMMAND:
if ( LOWORD(wParam) == IDOK
|| LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, TRUE);
return (TRUE);
}
break;
}
return (FALSE);
}
Функция CreateThread создает новую нить внутри текущего процесса. Эта функция дает процессу возможность распределить работу, выполняемую приложением, но нескольким нитям ради ускорения времени выполнения приложения. Нити, как правило, используются для выполнения фоновых задач, в частности, для разбиения текста на страницы, выполняемого текстовым редактором. С помощью нитей подобное разбиение на страницы происходит по мере ввода пользователем текста документа, причем пользователь не ощущает в этом случае никаких задержек.
Нити разделяют вместе с процессом общее адресное пространство и системные ресурсы. Однако у них имеется собственный стек, а в Windows NT/2000 – и собственные дескрипторы защиты. Для создания нити требуется следующая информация:
* Размер стека нити
* Атрибуты защиты нити. Для указания установленной по умолчанию защиты в Windows NT/2000 либо в среде Windows 9.x, где защита не поддерживается, можно использовано значение NULL.
* Адрес процедуры, с которой начинается выполнение. Это должна быть функция, которая получает в качестве единственного параметра 32-разрядное значение.
* Дополнительное 32-разрядное значение, которое передается в процедуру нити.
* Флаги, которые, помимо прочего, допускают установку уровня приоритета нити.
* Адрес для хранения идентификатора нити. Идентификатор нити представляет собой уникальное системное значение.
После вызова приложением функции CreateThread для создания новой нити эта функция возвращает дескриптор нового объекта нити. Этот дескриптор используется для управления нитью, а кроме того, он предоставляет вызывающему процессу возможность удаления нити, если в этом возникнет потребность. Пример создания нитей с помощью функции CreateThread приведен в описании указанной функции далее в главе.