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