Мьютекс - это концепция программирования, которая часто используется для решения задач многопоточности. Мой вопрос к сообществу:
Что такое мьютекс и как его использовать?
Мьютекс - это концепция программирования, которая часто используется для решения задач многопоточности. Мой вопрос к сообществу:
Что такое мьютекс и как его использовать?
Когда у меня на работе идет жаркая дискуссия, я использую резинового цыпленка, который держу на столе как раз для таких случаев. Человек, держащий курицу, - единственный человек, которому разрешено говорить. Если вы не держите курицу, вы не можете говорить. Вы можете только указать, что хотите курицу, и подождать, пока она у вас получится, прежде чем говорить. Когда вы закончите говорить, вы можете передать курицу обратно модератору, который передаст ее следующему человеку, который будет говорить. Это гарантирует, что люди не разговаривают друг с другом, а также у них будет собственное пространство для разговора.
Замените Chicken на Mutex и person на thread, и вы получите концепцию мьютекса.
Конечно, резиновых мьютексов не существует. Только резиновая курица. У моих кошек когда-то была резиновая мышь, но они ее съели.
Конечно, прежде чем использовать резинового цыпленка, вы должны спросить себя, действительно ли вам нужно 5 человек в одной комнате, и не будет ли проще, если один человек в комнате сам сделает всю работу. На самом деле, это просто продолжение аналогии, но вы поняли идею.
Мьютекс - это взаимоисключающий флаг. Он действует как привратник для раздела кода, разрешая одному потоку и блокируя доступ всем остальным. Это гарантирует, что управляемый код будет обрабатываться только одним потоком за раз. Просто не забудьте отпустить мьютекс, когда закончите. :)
Mut ual Ex clusion. Вот запись об этом в Википедии.
Задача мьютекса - синхронизировать два потока. Когда у вас есть два потока, пытающихся получить доступ к одному ресурсу, общий шаблон состоит в том, чтобы первый блок кода пытался установить мьютекс перед вводом кода. Когда второй блок кода пытается получить доступ, он видит, что мьютекс установлен, и ждет, пока первый блок кода не будет завершен (и не снимает мьютекс), затем продолжает.
Конкретные детали того, как это делается, очевидно, сильно различаются в зависимости от языка программирования.
Когда у вас есть многопоточное приложение, разные потоки иногда используют общий ресурс, такой как переменная или аналогичный. К этому общему источнику часто невозможно получить доступ одновременно, поэтому необходима конструкция, гарантирующая, что только один поток использует этот ресурс одновременно.
Эта концепция называется «взаимное исключение» (сокращенно Mutex) и представляет собой способ гарантировать, что внутри этой области разрешен только один поток, используя этот ресурс и т. Д.
Их использование зависит от языка, но часто (если не всегда) зависит от мьютекса операционной системы.
Некоторым языкам эта конструкция не нужна из-за парадигмы, например функциональное программирование (хорошие примеры - Haskell, ML).
Что такое мьютекс?
Мьютекс (на самом деле термин «мьютекс» - сокращение от взаимного исключения), также известный как спин-блокировка, - это простейший инструмент синхронизации, который используется для защиты критических областей и, таким образом, предотвращения состояний гонки. То есть поток должен получить блокировку перед входом в критическую секцию (в критической секции несколько потоков совместно используют общую переменную, обновляя таблицу, записывая файл и т. Д.), Он снимает блокировку, когда покидает критическую секцию.
Что такое состояние гонки?
Состояние гонки возникает, когда два или более потока могут получить доступ к общим данным и пытаются изменить их одновременно. Поскольку алгоритм планирования потоков может переключаться между потоками в любое время, вы не знаете, в каком порядке потоки будут пытаться получить доступ к общим данным. Следовательно, результат изменения данных зависит от алгоритма планирования потоков, то есть оба потока стремятся получить доступ / изменить данные.
Пример из реальной жизни:
Когда у меня на работе идет жаркая дискуссия, я использую резиновую курицу, которую держу на столе как раз для таких случаев. Человек, держащий курицу, - единственный человек, которому разрешено говорить. Если вы не держите курицу, вы не можете говорить. Вы можете только указать, что хотите курицу, и подождать, пока она у вас получится, прежде чем говорить. Когда вы закончите говорить, вы можете передать курицу обратно модератору, который передаст ее следующему человеку, который будет говорить. Это гарантирует, что люди не разговаривают друг с другом, а также у них будет собственное пространство для разговора.
Замените Chicken на Mutex и person на thread, и вы получите концепцию мьютекса.
@Xetius
Использование в C #:
В этом примере показано, как локальный объект 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
Здесь есть отличные ответы, вот еще одна отличная аналогия, объясняющая, что такое мьютекс:
Рассмотрим одиночный туалет с клавишей. Когда кто-то входит, они берут ключ, а туалет занят. Если кому-то еще нужно воспользоваться туалетом, он должен подождать в очереди. Когда человек в туалете закончил, он передает ключ следующему человеку в очереди. Имеет смысл, правда?
Преобразуйте туалет в истории в общий ресурс, а ключ - в мьютекс. Взяв ключ от туалета (приобретите замок), вы сможете им воспользоваться. Если ключа нет (замок заблокирован), придется подождать. Когда человек возвращает ключ (снимите блокировку), вы можете получить его прямо сейчас.
В C # обычно используется мьютекс Monitor. Тип - "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. Предположим, у вас есть многопоточная программа и у вас есть два потока. Теперь у вас в очереди заданий одно задание. Первый поток проверит очередь заданий и, найдя задание, начнет его выполнять. Второй поток также проверит очередь заданий и обнаружит, что в очереди есть одно задание. Таким образом, он также назначит тот же указатель задания. Итак, что происходит: оба потока выполняют одно и то же задание. Это вызовет ошибку сегментации. Это пример состояния гонки.
Решение этой проблемы - MUTEX. MUTEX - это своего рода блокировка, которая блокирует один поток за раз. Если другой поток хочет его заблокировать, он просто блокируется.
Ссылка на тему MUTEX в этом pdf-файле действительно заслуживает внимания.
Мьютексы полезны в ситуациях, когда вам нужно обеспечить эксклюзивный доступ к ресурсу через несколько процессов, где обычная блокировка не поможет, поскольку она работает только между потоками.
Mutex: Mutex означает Mut ual Ex clusion. Это означает, что только один процесс / поток может войти в критическую секцию одновременно. При параллельном программировании несколько потоков / процессов, обновляющих общий ресурс (любую переменную, общую память и т. Д.), Может привести к неожиданному результату. (Поскольку результат зависит от того, какой поток / процесс получает первый доступ).
Чтобы избежать такого неожиданного результата, нам нужен какой-то механизм синхронизации, который гарантирует, что только один поток / процесс получает доступ к такому ресурсу одновременно.
Библиотека 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
Это структура для типа данных мьютекса, то есть pthread_mutex_t. Когда мьютекс заблокирован, __lock устанавливается на 1. Когда он разблокирован, __lock устанавливается на 0.
Это гарантирует, что никакие два процесса / потока не смогут получить доступ к критическому разделу одновременно.