Мутекс - це концепція програмування, яка часто використовується для розв’язання задач, що мають багато ниток. Моє запитання до громади:
Що таке мутекс і як ним користуватися?
Мутекс - це концепція програмування, яка часто використовується для розв’язання задач, що мають багато ниток. Моє запитання до громади:
Що таке мутекс і як ним користуватися?
Відповіді:
Коли у мене велика гаряча дискусія на роботі, я використовую гумову курку, яку я тримаю в своєму столі просто для таких випадків. Особа, яка тримає курку, - єдина людина, якій дозволено розмовляти. Якщо ви не тримаєте курку, ви не можете говорити. Ви можете лише вказати, що хочете курку, і чекати, поки ви її отримаєте, перш ніж говорити. Після того, як ви закінчите говорити, ви можете передати курку назад модератору, який передасть її наступній людині, щоб говорити. Це гарантує, що люди не говорять один над одним, а також мають свій простір для розмови.
Замініть курку на Mutex та людину ниткою, і ви, в основному, маєте поняття мютекс.
Звичайно, немає такого поняття, як гумова мутекс. Тільки гумова курка. У моїх котів колись була гумова миша, але вони її їли.
Звичайно, перед тим, як використовувати гумову курку, потрібно запитати себе, чи вам насправді потрібно 5 людей в одній кімнаті, і чи не просто було б просто з однією людиною в кімнаті самостійно виконати всю роботу. Власне, це лише розширення аналогії, але ви отримуєте думку.
Mutex - прапор взаємовиключного. Він виконує функцію захисника до розділу коду, що дозволяє ввести один потік і перекрити доступ до всіх інших. Це гарантує, що керований код буде одночасно потрапляти лише одним потоком. Просто не забудьте випустити мютекс, коли закінчите. :)
Взаємовиключення. Ось запис у Вікіпедії на ній:
http://en.wikipedia.org/wiki/Mutual_exclusion
Суть мутексу - синхронізація двох потоків. Коли у вас є два потоки, які намагаються отримати доступ до одного ресурсу, загальною схемою є перший блок коду, який намагається отримати доступ для встановлення mutex перед введенням коду. Коли другий блок коду намагається отримати доступ, він бачить, що mutex встановлений і чекає, поки перший блок коду буде завершений (і скасує мутекс), а потім продовжується.
Конкретні деталі того, як це здійснюється, очевидно сильно різняться залежно від мови програмування.
Коли у вас є багатопотокова програма, різні потоки іноді мають спільний ресурс, наприклад змінну чи подібний. До цього спільного джерела часто не можна одночасно звертатися, тому потрібна конструкція, яка забезпечує лише один потік, який використовує цей ресурс одночасно.
Концепція називається "взаємне виключення" (короткий Mutex), і це спосіб забезпечити, щоб всередині цієї області було дозволено лише одну нитку, використовуючи цей ресурс тощо.
Як ними користуватися, залежить від мови, але часто (якщо не завжди) базується на мутексі операційної системи.
Деяким мовам ця конструкція не потрібна через парадигму, наприклад, функціональне програмування (Haskell, ML - хороші приклади).
У C # поширений мутекс - це Монітор . Тип - " System.Threading.Monitor ". Він також може бути використаний неявно через оператор ' lock (Object) '. Одним із прикладів його використання є побудова класу Singleton.
private static readonly Object instanceLock = new Object();
private static MySingleton instance;
public static MySingleton Instance
{
lock(instanceLock)
{
if(instance == null)
{
instance = new MySingleton();
}
return instance;
}
}
Оператор блокування за допомогою об'єкта приватного блокування створює критичний розділ. Вимагаючи від кожної нитки зачекати, поки попередній не буде закінчений. Перший потік увійде в розділ і ініціалізує екземпляр. Другий потік зачекає, потрапить у розділ та отримає ініціалізований екземпляр.
Будь-який тип синхронізації статичного члена може використовувати оператор блокування аналогічно.
Що таке Мутекс ?
Мутекс (насправді, термін mutex короткий для взаємного виключення) також відомий як спінлок - це найпростіший інструмент синхронізації, який використовується для захисту критичних областей і, таким чином, запобігання перегонів. Тобто потік повинен придбати замок перед входом у критичний розділ (У критичному розділі багато потоків мають спільну змінну, оновлення таблиці, написання файлу тощо), він випускає блокування, коли залишає критичний розділ.
Що таке перегони ?
Умова перегонів виникає, коли два або більше потоків можуть отримати доступ до спільних даних і вони намагаються змінити їх одночасно. Оскільки алгоритм планування потоків може змінюватися між потоками в будь-який час, ви не знаєте, в якому порядку потоки будуть намагатися отримати доступ до спільних даних. Отже, результат зміни даних залежить від алгоритму планування потоків, тобто обидва потоки "гоняться" для доступу / зміни даних.
Приклад із реального життя:
Коли у мене велика гаряча дискусія на роботі, я використовую гумову курку, яку я тримаю в своєму столі просто для таких випадків. Особа, яка тримає курку, - єдина людина, якій дозволено розмовляти. Якщо ви не тримаєте курку, ви не можете говорити. Ви можете лише вказати, що хочете курку, і чекати, поки ви її отримаєте, перш ніж говорити. Після того, як ви закінчите говорити, ви можете передати курку назад модератору, який передасть її наступній людині, щоб говорити. Це гарантує, що люди не говорять один над одним, а також мають свій простір для розмови.
Замініть курку на Mutex та людину ниткою, і ви, в основному, маєте поняття мютекс.
@Xetius
Використання в C #:
Цей приклад показує, як локальний об’єкт Mutex використовується для синхронізації доступу до захищеного ресурсу. Оскільки кожен потік виклику блокується, поки він не набуде права власності на mutex, він повинен викликати метод ReleaseMutex, щоб звільнити право власності на потік.
using System;
using System.Threading;
class Example
{
// Create a new Mutex. The creating thread does not own the mutex.
private static Mutex mut = new Mutex();
private const int numIterations = 1;
private const int numThreads = 3;
static void Main()
{
// Create the threads that will use the protected resource.
for(int i = 0; i < numThreads; i++)
{
Thread newThread = new Thread(new ThreadStart(ThreadProc));
newThread.Name = String.Format("Thread{0}", i + 1);
newThread.Start();
}
// The main thread exits, but the application continues to
// run until all foreground threads have exited.
}
private static void ThreadProc()
{
for(int i = 0; i < numIterations; i++)
{
UseResource();
}
}
// This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
private static void UseResource()
{
// Wait until it is safe to enter.
Console.WriteLine("{0} is requesting the mutex",
Thread.CurrentThread.Name);
mut.WaitOne();
Console.WriteLine("{0} has entered the protected area",
Thread.CurrentThread.Name);
// Place code to access non-reentrant resources here.
// Simulate some work.
Thread.Sleep(500);
Console.WriteLine("{0} is leaving the protected area",
Thread.CurrentThread.Name);
// Release the Mutex.
mut.ReleaseMutex();
Console.WriteLine("{0} has released the mutex",
Thread.CurrentThread.Name);
}
}
// The example displays output like the following:
// Thread1 is requesting the mutex
// Thread2 is requesting the mutex
// Thread1 has entered the protected area
// Thread3 is requesting the mutex
// Thread1 is leaving the protected area
// Thread1 has released the mutex
// Thread3 has entered the protected area
// Thread3 is leaving the protected area
// Thread3 has released the mutex
// Thread2 has entered the protected area
// Thread2 is leaving the protected area
// Thread2 has released the mutex
Тут є кілька чудових відповідей, ось ще одна чудова аналогія для пояснення, що таке мутекс :
Розглянемо одиночний туалет з ключем . Коли хтось заходить, вони беруть ключ і туалет зайнятий . Якщо комусь потрібно скористатися туалетом, їм потрібно чекати в черзі . Коли людина в туалеті зроблена , вони передають ключ черговій людині в черзі. Має сенс, правда?
Перетворіть туалет у сюжеті на загальний ресурс та ключ на мютекс . Якщо взяти ключ до туалету (придбати замок), ви можете ним користуватися. Якщо ключа немає (замок заблокований), вам доведеться почекати. Коли особа поверне ключ ( відпустіть замок ), ви можете зараз придбати його.
Щоб зрозуміти MUTEX, спочатку ви повинні знати, що таке "стан перегонів", а потім лише ви зрозумієте, для чого потрібен MUTEX. Припустимо, у вас є багатопотокова програма і у вас є дві нитки. Тепер у вас є одна робота в черзі. Перший потік перевірить чергу завдань, а після пошуку роботи він почне виконувати її. Другий потік також перевірить чергу завдань і виявить, що в черзі є одне завдання. Отже, він також призначить той же покажчик завдання. Отже, тепер, що відбувається, обидва потоки виконують одну і ту ж роботу. Це призведе до помилки сегментації. Це приклад стану гонки.
Рішення цієї проблеми - MUTEX. MUTEX - це вид замка, який замикає по одній нитці одночасно. Якщо інша нитка хоче її заблокувати, нитка просто блокується.
Тему MUTEX у цьому посиланні на файл PDF дійсно варто прочитати.
Mutex: Mutex розшифровує поняття Mut ual Ex . Це означає, що один процес / потік може входити в критичний розділ. У паралельному програмуванні, де кілька потоків / процес намагається оновити спільний ресурс (будь-яка змінна, спільна пам'ять тощо) може призвести до несподіваного результату. (Оскільки результат залежить від того, який потік / процес отримує перший доступ).
Щоб уникнути такого несподіваного результату, нам потрібен механізм синхронізації, який гарантує, що лише один потік / процес отримує доступ до такого ресурсу одночасно.
Бібліотека pthread забезпечує підтримку Mutex.
typedef union
{
struct __pthread_mutex_s
{
***int __lock;***
unsigned int __count;
int __owner;
#ifdef __x86_64__
unsigned int __nusers;
#endif
int __kind;
#ifdef __x86_64__
short __spins;
short __elision;
__pthread_list_t __list;
# define __PTHREAD_MUTEX_HAVE_PREV 1
# define __PTHREAD_SPINS 0, 0
#else
unsigned int __nusers;
__extension__ union
{
struct
{
short __espins;
short __elision;
# define __spins __elision_data.__espins
# define __elision __elision_data.__elision
# define __PTHREAD_SPINS { 0, 0 }
} __elision_data;
__pthread_slist_t __list;
};
#endif
Це структура для типу даних mutex, тобто pthread_mutex_t. Коли mutex заблоковано, __lock встановлюється на 1. Коли він розблокований, __lock встановлюється на 0.
Це гарантує, що жоден два процеси / потоки не можуть отримати доступ до критичного розділу одночасно.