Remove ads
З Вікіпедії, вільної енциклопедії
М'ю́текс (англ. mutex, від англ. mutual exclusion — взаємне виключення) призначено для захисту певного об’єкта у потоці від доступу інших потоків. М'ютекс є одним із засобів синхронізації роботи потоків або процесів[1].
М'ютекси є одним з варіантів семафорних механізмів для організації взаємного виключення. Вони реалізовані в багатьох ОС, їхнє основне призначення — організація взаємного виключення для потоків з одного і того ж або різних процесів.
М'ютекси — це прості двійкові семафори, які можуть перебувати в одному з двох станів - сигнальному або несигнальному (відкритий і закритий відповідно). Коли потік отримує м'ютекс, той переводиться в несигнальний стан.
Організація послідовного доступу до ресурсів з використанням м'ютексів стає нескладною, оскільки в кожен конкретний момент тільки один потік може володіти цим об'єктом. Для того, щоб об'єкт mutex став доступний потокам, що належать різним процесам, при створенні йому необхідно присвоїти ім'я. Потім це ім'я потрібно передати «у спадок» завданням, які повинні його використовувати для взаємодії. Для цього вводяться спеціальні системні виклики (наприклад CreateMutex у Windows), в яких указується початкове значення м'ютекса і його ім'я. Для роботи з м'ютексом є кілька функцій. Крім вже згаданої функції створення такого об'єкта (CreateMutex), є функції відкриття (OpenMutex) і функція звільнення цього об'єкта (ReleaseMutex). Конкретні звернення до цих функцій і переліки передаваних і отримуваних параметрів потрібно дивитися в документації на відповідну ОС.
Порівняно з критичною секцією його функціональність дещо розширена. М’ютекси можуть мати імена і дескриптори. Вони є об’єктами ядра (в той час як критичні секції належать процесу), тому їх можна використовувати для синхронізації потоків із різних процесів. Наприклад, два процеси, які розділяють спільну пам’ять через відображення файлів, можуть використовувати м’ютекс для синхронізації доступу до неї. Так як м’ютекси є об’єктами ядра і мають складнішу реалізацію, на їх обробку, як правило, витрачається більше часу порівняно з критичними секціями. Тому, якщо потрібно синхронізувати роботу потоків одного процесу, варто користуватися критичними секціями.
М’ютекс перебуває в сигнальному стані тільки тоді, коли він не належить жодному із процесів. Як тільки хоча б один процес запитує володіння м’ютексом, він переходить у несигнальний стан і залишається в ньому доти, поки не буде звільнений власником. На відміну від критичних секцій, м’ютекси дозволяють задавати точний інтервал очікування, а м’ютекси, залишені закінченими процесами, автоматично переходять у сигнальний стан. Для створення м’ютекса використовується функція CreateMutex. Її опис мовою C[2]:
HANDLE WINAPI CreateMutex( __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes, __in BOOL bInitialOwner, __in_opt LPCTSTR lpName )
function CreateMutex( lpMutexAttributes: PSecurityAttributes; // Атрибути доступу bInitialOwner: BOOL; // Задає, чи буде процес володіти // м’ютексом відразу після створення lpName: PChar // Ім'я м’ютекса ): THandle
Функція повертає дескриптор створеного м’ютекса (або 0 при невдалому завершенні). Якщо м’ютекс із заданим ім'ям вже існує, повертається його дескриптор. У цьому випадку функція API GetLastError поверне код помилки ERROR_ALREDY_EXISTS. Ім'я не повинно збігатися з ім'ям уже існуючого об'єкта типу Semaphore, Event, Job, Waitable Timer або File Mapping. Ім’я може мати префікс "Global\" або "Local\", які відповідно вказують на створення об’єкта у глобальному або сесійному просторі імен. Якщо невідомо, чи існує вже м’ютекс із заданим ім'ям, програма не повинна запитувати володіння об'єктом при створенні (тобто повинна передати значення false як bInitialOwner).
Якщо м’ютекс уже існує, програма може отримати його дескриптор функцією OpenMutex. Її опис на C[3]:
HANDLE WINAPI OpenMutex( __in DWORD dwDesiredAccess, __in BOOL bInheritHandle, __in LPCTSTR lpName )
function OpenMutex( dwDesiredAccess: DWORD; // Задає права доступу до об'єкта bInheritHandle: BOOL; // Задає, чи може об'єкт успадковуватися // дочірніми процесами lpName: PChar // Ім'я м’ютекса ): THandle
Параметр dwDesiredAccess може набувати одне з таких значень:
Функція повертає дескриптор відкритого м’ютекса, або 0 у випадку помилки.
Потік захоплює володіння м’ютексом через виклик однієї з функцій очікування (WaitForSingleObject, WaitForMultipleObjects тощо) відносно дескриптора м’ютекса.
Вивільняється м’ютекс за допомогою функції ReleaseMutex. Її визначення на C[4]:
BOOL WINAPI ReleaseMutex(__in HANDLE hMutex);
function ReleaseMutex(hMutex: THandle): BOOL;
Нижче приведено фрагмент коду потоку[1] (мовою Delphi), який збільшує на 1 спільну для кількох потоків змінну А. Приклад передбачає, що існує кілька потоків, які виконують таку ж дію. Перед звертанням до спільної змінної потік очікує на звільнення м'ютекса. Якщо такої синхронізації не використовувати, то виникатиме конкуренція потоків.
const MutexName = 'IMut'; .............................. function ThreadFunc(Ptr: Pointer): LongInt; var I : integer; hIMut : THandle; begin for I := 1 to 1000000 do begin // Якийсь код hIMut := CreateMutex(0, false, MutexName); WaitForSingleObject(hIMut, INFINITE); Inc(A); ReleaseMutex(hIMut); // Якийсь код end; end;
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.