EnterCriticalSection, LeaveCriticalSection и InitializeCriticalSection

Давайте посмотрим пример. Следующий код выполянет ряд действий над массивом.

// 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

Потоки запускаются, начинается доступ к критичекой секции. Дожидаются своей очереди и выполняют необходимые действия.

 
« Предыдущая статья   Следующая статья »