- •Лекция 9,10. Примитивы синхронизации вWin32 api
- •Функции ожидания
- •Взаимное исключение (mutex)
- •Использование объекта mutex
- •Семафор
- •Использование семафора
- •Событие
- •Использование событий
- •Ожидаемый таймер
- •Неименованый канал (магистраль) - Anonymous pipe
- •Наследование дескрипторов
- •Именованый канал – Named Pipe
- •Пример: Многонитевой сервер каналов.
Использование объекта mutex
Можно использовать mutex для защиты общего ресурса от одновременного доступа многими нитями. Каждая нить должна ждать освобождения mutex прежде, чем выполнять код, в котором осуществляется доступ к общему ресурсу. Например, если несколько нитей, обращаются к базе данных, нити могут использовать mutex, чтобы разрешить только одной нити в любой момент времени модифицировать базу данных.
BOOL WriteToDatabase(HANDLE hMutex)
{
DWORD dwWaitResult;
dwWaitResult = WaitForSingleObject( hMutex, 5000L);
switch (dwWaitResult)
{
case WAIT_OBJECT_0: // нить владеет объектом mutex.
//***********************
// Запись в базу данных.
//***********************
// Освобождаем mutex.
if (! ReleaseMutex(hMutex)) {
// Обработка ошибки.
}
break;
}
case WAIT_TIMEOUT: // Истекло время ожидания (5 сек).
return FALSE;
}
return TRUE;
}
Семафор
Объект семафор - объект синхронизации, который поддерживает счетчик между нулем и указанным максимальным значением. Состояние семафора устанавливается «сигнализированным», когда счетчик больше нуля, и «несигнализированным», когда счетчик нулевой.
Нить использует функцию CreateSemaphore, чтобы создать объект. Нити в других процессах могут открывать дескриптор к существующему объекту семафора, определяя его имя в вызове OpenSemaphore. Нити, которые ожидают семафор, помещаются в очередь в порядке поступления.
Каждый раз при возврате из wait функции счетчик семафора уменьшен на один. Функция ReleaseSemaphore увеличивает счетчик семафора на указанное количество. Счетчик никогда не может быть меньше нуля или больше максимального значения.
В отличие от объекта mutex, функцию ReleaseSemaphore может использовать любая нить, чтобы увеличить счетчик семафора.
Использование семафора
В следующем примере, процесс использует семафор для ограничения числа создаваемых окон.
HANDLE hSemaphore;
LONG cMax = 10;
LONG cPreviousCount;
// Create a semaphore with initial and max. counts of 10.
hSemaphore = CreateSemaphore(
NULL, // no security attributes
cMax, // initial count
cMax, // maximum count
NULL); // unnamed semaphore
if (hSemaphore == NULL) { // Check for error. }
// Try to enter the semaphore gate.
dwWaitResult = WaitForSingleObject( hSemaphore, 0L);
switch (dwWaitResult) {
case WAIT_OBJECT_0: // The semaphore object was signaled.
// OK to open another window.
break;
case WAIT_TIMEOUT: // А time-out occurred.
// Cannot open another window.
break;
}
// When thread closes a window, increment the count of the semaphore.
if (!ReleaseSemaphore(
hSemaphore, // handle to semaphore
1, // increase count by one
NULL) ) // not interested in previous count
{
// Deal with the error.
}
Событие
Объект события - объект синхронизации, состояние которого может быть явно установлено сигнализированным при помощи функции SetEvent или PulseEvent. Существуют два типа событий.
События с ручным сбросом.События, состояние которых остается сигнализированным, пока явно не сброшено вызовом функцией ResetEvent. В то время как состояние объекта сигнализировано, любое число ожидающих нитей могут быть освобождены.
События с автоматическим сбросом.События, состояние которых остается «сигнализирован» до момента выполнения функции wait, в это время система автоматически сбрасывает состояние «сигнализирован». Если никакие нити не ожидают данное событие, то его состояние остается «сигнализирован».
Нить использует функцию CreateEvent, чтобы создать объект при этом определяется начальное состояние объекта и тип события (с ручным или автоматическим сбросом). Можно также определить имя объекта, тогда нити в других процессах могут открывать дескриптор к существующему объекту в вызове функции OpenEvent.
Нить может использовать функцию PulseEvent, чтобы установить состояние « сигнализирован » и затем сбросить его после завершения функции wait. Для событий с ручным сбросом, все ожидающие нити освобождаются. Для событий с автоматическим сбросом, освобождается только одна нить, даже если это событие ожидают несколько нитей. Если никто не ждет события, то PulseEvent не имеет никаких последствий.
