Модели потоков. Объекты синхронизации. Мьютексы

   
На этом шаге мы дадим определение мьютекса и рассмотрим области его использования.

   
Мъютекс (mutex - mutually exclusive) - это объект синхронизации, который находится в сигнальном состоянии только
тогда, когда он не принадлежит ни одному из процессов. Как только хотя бы один процесс запрашивает владение мьютексом, последний
переходит в несигналыюе состояние и остается в нем до тех пор, пока не будет освобожден владельцем. Такое поведение позволяет использовать
мьютексы для синхронизации совместного доступа нескольких процессов к разделяемому ресурсу. Для создания мьютекса используется функция:

function CreateMutex(
  lpMutexAttributes: PSecurityAttributes;
    // Адрес структуры TSecurityAttributes
  bInitialOwner: BOOL;
    // Указывает, будет ли процесс владеть мьютексом сразу после создания
  lpName: PChar
    // Имя мьютекса 
): THandle; stdcall;

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

   
Если неизвестно, существует ли уже мьютекс с таким именем, программа не должна запрашивать владение объектом при создании (то есть
должна передать в параметре bInitialOwner значение False).

   
Если мьютекс уже существует, приложение может получить его идентификатор с помощью функции OpenMutex:

function OpenMutex(
  dwDesiredAccess: DWORD;
    // Задает права доступа к объекту
  bInheritHandle: BOOL;
    // Задает, может ли объект наследоваться дочерними процессами
  lpName: PChar
    // Имя объекта 
): THandle; stdcall;

   
Параметр dwDesiredAccess может принимать одно из следующих значений:

  • MUTEX_ALL_ACCESS - приложение получает полный доступ к объекту;
  • SYNCHRONIZE (только для Windows NT) - приложение может использовать
    объект только в функциях ожидания и в функции ReleaseMutex.

   
Функция возвращает либо идентификатор мьютекса, установленного в сигнальное состояние, либо 0 в случае ошибки. Мьютекс переходит в сигнальное
состояние после срабатывания функции ожидания, в которую был передан его идентификатор. Для возвращения в несигнальное состояние служит функция:

  function ReleaseMutex(hMutex: THandle): BOOL; stdcall;

   
Если несколько процессов обмениваются данными, например, через файл, отображенный на память, каждый из них для корректного доступа
к общему ресурсу должен содержать следующий код:

var
  Mutex: THandle;

// При инициализации программы
Mutex := CreateMutex(nil, False, 'UniqueMutexName');
if Mutex = 0 then
  RaiseLastWin32Error;
.   .   .
// Доступ к ресурсу
WaitForSingleObject(Mutex, INFINITE);
try
  // Доступ к ресурсу, захват мьютекса гарантирует,
  // что остальные процессы, пытающиеся получить доступ,
  // будут остановлены на функции WaitForSingleObject
.   .   .
finally
  // Работа с ресурсом окончена, 
  // освобождаем его для остальных процессов
  ReleaseMutex(Mutex);
end;
.   .   .
// При завершении программы
CloseHandle(Mutex);

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

   
Разумеется, если работа с ресурсом может потребовать значительного времени, то необходимо либо использовать функцию
MsgWaitForSingleObject, либо вызывать функцию WaitForSingleObject в цикле с нулевым периодом ожидания, проверяя
код возврата. В противном случае приложение окажется "замороженным". Всегда защищайте захват-освобождение объекта синхронизации
при помощи блока try...finally, иначе ошибка во время работы с ресурсом приведет к блокированию всех процессов, ожидающих его освобождения.

   
На следующем шаге мы рассмотрим семафоры.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий