Очень полезно сначала прочитать "Шаг 80 - Что такое критическая секция (Critical Section)", так как именно эти функции относятся к критической секции. Давайте посмотрим пример. Следующий код выполянет ряд действий над массивом.
// TestCritical.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "windows.h" #include "iostream.h" #define MAX_ARRAY 5 int array[MAX_ARRAY]; void EmptyArray(); void PrintArray(); void FullArray(); void main() { EmptyArray(); PrintArray(); FullArray(); PrintArray(); EmptyArray(); PrintArray(); } void EmptyArray() { for (int x=0;x<(MAX_ARRAY+1); x++) array[x]=0; Sleep(1000); } void PrintArray() { for (int x=0;x<(MAX_ARRAY+1); x++) cout << array[x] << " "; cout << endl; Sleep(1000); } void FullArray() { for (int x=0;x<(MAX_ARRAY+1); x++) array[x]=x; Sleep(1000); }
В данном примере все нормально. У нас всего один поток. Этот поток последовательно выполнит все действия над распределенным объектом array. Почему он распределенный ? Потому, что он определен глобально и к нему можно обратиться в любой момент. Так вот, если у нас будет несколько потоков все станет сложнее. Одна фунция не успеет очистить массив, а вторая может уже начать писать или печатать не до конца очищенный массив. Вот для решения этих проблем и используются критические секции. В тот код, который правит распределенный ресурс и является критической секцией. Для объявления начала критической секции используется функция.
VOID EnterCriticalSection ( LPCRITICAL_SECTION lpCriticalSection // указатель на переменную критическая секция );
А для выхода из критической секции.
VOID LeaveCriticalSection ( LPCRITICAL_SECTION lpCriticalSection // указатель на переменную критическая секция );
Для работы с критической секцией нам нужна переменная типа - критическай секция. Вот она:
CRITICAL_SECTION
Перед тем как использовать критическую секцию ее надо проинициализировать.
VOID InitializeCriticalSection ( LPCRITICAL_SECTION lpCriticalSection // указатель на переменную критическая секция );
Давайте переделаем наш пример в многопоточное приложение с критическими секциями.
// TestCritical.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "windows.h" #include "iostream.h" #include "process.h" #define MAX_ARRAY 5 CRITICAL_SECTION critsect; int array[MAX_ARRAY]; void EmptyArray(void *); void PrintArray(void *); void FullArray(void *); void main() { InitializeCriticalSection(&critsect); if (_beginthread(EmptyArray,1024,NULL)==-1) cout << "Error begin thread " << endl; if (_beginthread(PrintArray,1024,NULL)==-1) cout << "Error begin thread " << endl; if (_beginthread(FullArray,1024,NULL)==-1) cout << "Error begin thread " << endl; if (_beginthread(PrintArray,1024,NULL)==-1) cout << "Error begin thread " << endl; if (_beginthread(EmptyArray,1024,NULL)==-1) cout << "Error begin thread " << endl; if (_beginthread(PrintArray,1024,NULL)==-1) cout << "Error begin thread " << endl; Sleep(10000); } void EmptyArray(void *) { cout << "EmptyArray" << endl; EnterCriticalSection(&critsect); for (int x=0;x<(MAX_ARRAY+1); x++) array[x]=0; Sleep(1000); LeaveCriticalSection(&critsect); _endthread(); } void PrintArray(void *) { cout << "PrintArray" << endl; EnterCriticalSection(&critsect); for (int x=0;x<(MAX_ARRAY+1); x++) cout << array[x] << " "; cout << endl; Sleep(1000); LeaveCriticalSection(&critsect); _endthread(); } void FullArray(void *) { cout << "FullArray" << endl; EnterCriticalSection(&critsect); for (int x=0;x<(MAX_ARRAY+1); x++) array[x]=x; Sleep(1000); LeaveCriticalSection(&critsect); _endthread(); }
Результат работы будет вот такой:
EmptyArray PrintArray FullArray PrintArray EmptyArray PrintArray 0 0 0 0 0 0 0 1 2 3 4 5 0 0 0 0 0 0
Потоки запускаются, начинается доступ к критичекой секции. Дожидаются своей очереди и выполняют необходимые действия. Не забудьте установиь опции многопоточного проекта, как в шаге ActiveX: "Шаг 78 - Что понимается под условиями гонки (rase condition) ?".