
- •Лабораторная работа № 3. Синхронизация потоков с использованием мfс
- •Задача синхронизации потоков
- •Создание и синхронизация потоков с использованием mfc
- •1. Синхронизация с использованием глобальной переменной
- •3. Взаимодействие с помощью объектов событий
- •1. Критические секции.
- •2. Мьютексы.
- •3. Семафор
- •Создание и выполнение потоков
- •Функция WaitForSingleObject
- •Cинхронизация в mfc
- •Cинхронизация в cMutex
- •Задания для самостоятельного выполнения.
3. Взаимодействие с помощью объектов событий
Объект событий CEvent может находится в одном из двух состояний – сигнализирует или молчит. Потоки отслеживают момент, когда объект события начинает сигнализировать, и начинаю выполнение операций.
CEvent ThreadStart; //объект автоматически устанавливается в состояние молчания
ThreadStart.SetEvent(); //установка состояния сигнализации
Отслеживание состояния объекта осуществляется с помощью функции WinAPI WaitForSingleObject();
:: WaitForSingleObject(ThreadStart.m_hObject,INFINITE);
- первый параметр – дескриптор отслеживаемого события.
- второй параметр – время отслеживания. INFINITE – бесконечно.
В момент установки события WaitForSingleObject() вернет управление потоку.
В момент сброса события поток должен прекратить свою работу.
Для этого надо организовать постоянный опрос состояния события.
Это можно сделать следующим способом:
::WaitForSingleObject(ThreadStart.m_hObject,0);
Время 0 говорит о том, что надо опросить событие.
Если результат вызова этой функции равен WAIT_OBJECT_0, то объект в остоянии сигнализации. В других случаях – молчит.
CEvent ThreadStart; //Объект начала работы потока
CEvent ThreadEnd; //Объект окончания работы потока
UINT ThreadProc(LPVOID param) //Создание потоковой функции
{:: WaitForSingleObject(ThreadStart.m_hObject,INFINITE); //ожидание запуска потока
::MessageBox((HWND)param, ”Thread activated”,”Message from thread”,MB_OK);
bool Running=true;
int result;
while(Running){//Выполнение опреаций
result=:: WaitForSingleObject(ThreadEnd.m_hObject,0); //проверка завершения
if(result==WAIT_OBJECT_0)
Running=false;
}
::PostMessage((HWND)param,WM_CLOSE,0,0); //Сообщение
return 0;
}
Start() //запуск потока
{ThreadStart.SetEvent();
}
End() //завершение потока
{ThreadEnd.SetEvent();}
Поток нужно создавать независимо от состояния событий.
Синхронизация работы нескольких потоков
Для синхронизации нескольких потоков используют следующие объекты: критические секции, семафоры, мьютексы.
1. Критические секции.
Критические секции используются для контроля доступа к защищенным данным.
Их можно использовать внутри одного класса для синхронизации чтения-доступа к данным.
class cls
{private:
int val;
CCriticalSection section;
public:
void write(int);
void read(int*);
}
void cls::write(int n)
{section.Lock(); val=n; section.Unlock(); }
void cls::read(int * n) {section.Lock(); *n=val; section.Unlock(); }
При вызове метода Lock() происходит блокировка секции, и последующие вызовы этого метода не возвратят управление вызывающему потоку до тех пор, пока секция не будет освобождена.
Из данного примера видно, что при записи нового значения невозможно прочитать старое. Соответственно при чтении значения его невозможно изменить. Если в работе участвуют большие объемы данных, то для предотвращения сбоя необходим контроль. Критические секции обеспечивают минимальную защиту от сбоев.
2. Мьютексы.
Использование защелок CMutex при синхронизации потоков одного приложения не отличается от использования критических секций. Работа с ними осуществляется с использованием следующих объектов: CSingleLock и CMultiLock. Для получения доступа к защелке используется методо Lock(). Для освобождения защелки нужно вызвать метод Unlock()
CMutex mutex; //создание защелки
CSingleLock sLock(&mutex); //захват защелки
sLock.Lock();
sLock.Unlock(); //освобождение защелки
class cls
{private:
int val;
CMutex mutex;
public:
void write(int);
void read(int*);
}
void cls::write(int n)
{CSingleLock sLock(&mutex);
sLock.Lock();
val=n;
}
void cls::read(int * n)
{CSingleLock sLock(&mutex);
sLock.Lock();
*n=val;
}
Использование метода Unlock() в данном случае необязательно т.к. при вызове деструктора sLock защелка автоматически освобождается.