Давайте посмотрим пример. Следующий код выполянет ряд действий над массивом. // 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
Потоки запускаются, начинается доступ к критичекой секции. Дожидаются своей очереди и выполняют необходимые действия. |