Исключающий семафор (mutex)

Еще один вид синхронизаторов - исключающий семафор (мьютекс – mutual exclusion). Основное его отличие от критического раздела заключается в том, что последний можно использовать только в пределах одного процесса (одного запущенного приложения), а исключающими семафорами могут пользоваться разные процессы. Другими словами, критические разделы - это локальные объекты, которые доступны в рамках только одной программы, а исключающие семафоры могут быть глобальными объектами, позволяющими синхронизировать работу программ (т. е. разные запущенные приложения могут разделять одни и те же данные).

 
Рассмотрим основные функции для работы с объектами mutex.

1. Создание объекта mutex:

HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName);

Параметры:

lpMutexAttributes - указатель на структуру SECURITY_ATTRIBUTES (в Windows 95 данный параметр игнорируется);

bInitialOwner - указывает первоначальное состояние созданного объекта (TRUE - объект сразу становится занятым, FALSE - объект свободен);

lpName - указывает на строку, содержащую имя объекта. Имя необходимо для доступа к объекту других процессов, в этом случае объект становится глобальным и им могут оперировать разные программы. Если вам не нужен именованный объект, то укажите NULL. Функция возвращает указатель на объект mutex. В дальнейшем этот указатель используется для управления исключающим семафором.

2. HANDLE OpenMutex(DWORD dwDesiredAccess, // access flag

BOOL bInheritHandle, // inherit flag

LPCTSTR lpName // pointer to mutex-object name);

Позволяет получить указатель на мьютекс, открытый в другом разделе.

3. Закрытие (уничтожение) объекта mutex:

BOOL CloseHandle(HANDLE hObject)

3. Универсальная функция запроса доступа:

DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) - универсальная функция, предназначенная для запроса доступа к синхронизирующему объекту (в данном случае к объекту mutex).

Параметры:

hHandle - указатель на синхронизирующий объект (в данном случае передается значение, возвращенное функцией CreateMutex);

dwMilliseconds - время (в миллисекундах), в течение которого происходит ожидание освобождения объекта mutex. Если передать значение INFINITE (бесконечность), то функция будет ждать бесконечно долго.

Данная функция может возвращать следующие значения:

WAIT_OBJECT_0 - объект освободился;

WAIT_TIMEOUT - время ожидания освобождения прошло, а объект не освободился;

WAIT_ABANDON - произошел отказ от объекта (т. е. процесс, владеющий данным объектом, завершился, не освободив объект). В этом случае система (а не "процесс-владелец") переводит объект в свободное состояние. Такое освобождение объекта не предполагает гарантий защищенности данных;

WAIT_FAILED - произошла ошибка.

4. Освобождение объекта mutex:

BOOL ReleaseMutex(HANDLE hMutex) - освобождает объект mutex, переводя его из занятого в свободное состояние.

Посмотрим, как выглядит наш пример c критическими разделами, если переписать его, используя исключающие семафоры.

Листинг 2. Ограничение доступа к массиву с использованием исключающих семафоров

// Массив значений.

int mas[1000];

// Объект, регулирующий доступ к разделяемому коду.

HANDLE CritMutex;

{

...

// Инициализируем семафор разделяемого кода.

CritMutex = CreateMutex(NULL,FALSE,NULL);

... // Текст программы.

// Закрываем объект доступа к разделяемому коду.

CloseHandle(CritMutex);

}

// Первый поток: запись в массив данных.

DWORD WINAPI thread1(LPVOID par)

{ // Запись значений в массив.

// Запрос на вход в защищенный раздел.

DWORD dw = WaitForSingleObject(CritMutex,INFINITE);

if(dw == WAIT_OBJECT_0)

{ // Если объект освобожден корректно, то

// выполнение кода в защищенном разделе.

for(int i = 0;i<1000;i++)

{

mas[i] = i;

 
}

// Выход из защищенного раздела:

// освобождаем объект для доступа

// к защищенному разделу других задач.

ReleaseMutex(CritMutex);

}

return 0;

}

// Второй поток: считывание данных из массива.

DWORD WINAPI thread2(LPVOID par)

{ // Считывание значений из массива.

int j;

// Запрос на вход в защищенный раздел.

DWORD dw = WaitForSingleObject(CritMutex,INFINITE);

if(dw == WAIT_OBJECT_0)

{ // Если объект освобожден корректно, то

// выполнение кода в защищенном разделе.

for(int i = 0;i<1000;i++)

{

j = mas[i];

}

// Выход из защищенного раздела:

// освобождаем объект для доступа

// к защищенному разделу других задач.

ReleaseMutex(CritMutex);

}

return 0;

}

Исключающий семафор может быть занят неограниченное количество раз одним и тем же потоком.

https://mbo88.narod.ru/Ch9.html



Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: