Что такое мьютекс?

655

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

Что такое мьютекс и как вы его используете?

bmurphy1976
источник
2
Вот хорошая статья о разнице: barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore
Адам Дэвис
Учебник по мьютексу поможет разобраться: stackoverflow.com/questions/4989451/mutex-example-tutorial
Nav
1
Мьютекс подобен ключу от ванной на заправочной станции, гарантируя, что только один человек может пользоваться ванной за раз, и что никто другой не может пользоваться туалетом, пока текущий житель не закончил и ключ не был возвращен.
Йоншлинкерт

Ответы:

2154

Когда на работе я веду бурную дискуссию, я использую резинового цыпленка, которого держу в своем столе именно для таких случаев. Человек, держащий курицу, является единственным человеком, которому разрешено говорить. Если вы не держите курицу, вы не можете говорить. Вы можете только указать, что хотите курицу, и подождать, пока вы ее получите, прежде чем говорить. Как только вы закончите говорить, вы можете вернуть курицу модератору, который передаст ее следующему человеку, который будет говорить. Это гарантирует, что люди не разговаривают друг с другом, а также имеют свое собственное пространство для общения.

Замените Цыпленка на Мьютекс, а человека - на нить, и у вас в основном будет концепция мьютекса.

Конечно, не существует такого понятия, как резиновый мьютекс. Только резиновая курица. У моих кошек когда-то была резиновая мышь, но они ее съели.

Конечно, прежде чем использовать резиновую курицу, вам нужно спросить себя, нужно ли вам на самом деле 5 человек в одной комнате, и не будет ли проще, когда один человек в комнате сам выполняет всю работу. На самом деле, это просто продолжение аналогии, но вы поняли идею.

Xetius
источник
9
Отличный ответ. Можно ли утверждать, что на самом деле Mutex - это правила, которые останавливают прохождение курицы? а курица это то что ты запираешь?
SirYakalot
3
@SirYakalot, ты имеешь в виду, что курица - это ресурс, а модератор - мьютекс?
Оуэн
158
Курица - это мьютекс . Люди копят му ... курица - это конкурирующие темы . Модератор это ОС . Когда люди запрашивают курицу, они делают запрос блокировки. Когда вы вызываете mutex.lock (), ваш поток останавливается в lock () и отправляет запрос на блокировку ОС. Когда ОС обнаруживает, что мьютекс был освобожден из потока, она просто передает его вам и возвращает lock () - мьютекс теперь ваш и только ваш. Никто другой не сможет украсть его, потому что вызов lock () заблокирует его. Существует также try_lock (), которая будет блокировать и возвращать true, если mutex ваш, и сразу false, если mutex используется.
Петър Петров
4
Ты гений. Можете ли вы использовать резиновую куриную метафору для объяснения мониторов?
Риккардо
98
Иногда происхождение некоторых концепций программирования неясно. Новичок может задаться вопросом, почему все говорят о регулярных выражениях. Не очевидно, что регулярное выражение - это сокращение от [reg] ular [ex]. Точно так же мьютекс является сокращением для [взаимного] [бывшего] слияния. Это может облегчить усвоение значения термина. @TheSmurf ссылается на него в своем ответе, но было бы неплохо добавить его сюда в исторических целях.
Додзи Дзакума
138

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

Craig
источник
11
Мьютекс не имеет ничего общего с разделом кода как таковым, он защищает некоторый ресурс. Этот ресурс может быть сегментом кода, если мьютекс используется только вокруг этого кода, но в ту минуту, когда вы начнете использовать мьютекс в нескольких местах в вашем коде, ваше объяснение не будет выполнено. Обычно его также можно использовать для защиты некоторой структуры данных, к которой можно получить доступ из многих мест в коде.
paxdiablo
73

Взаимное исключение. Вот запись в Википедии:

http://en.wikipedia.org/wiki/Mutual_exclusion

Задача мьютекса - синхронизировать два потока. Когда два потока пытаются получить доступ к одному ресурсу, общая схема состоит в том, чтобы первый блок кода пытался получить доступ для установки мьютекса перед вводом кода. Когда второй блок кода пытается получить доступ, он видит, что мьютекс установлен, и ждет, пока первый блок кода не завершится (и отменяет установку мьютекса), а затем продолжает.

Конкретные детали того, как это достигается, очевидно, сильно зависит от языка программирования.

TheSmurf
источник
65

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

Эта концепция называется «взаимное исключение» (сокращение Mutex) и позволяет гарантировать, что в этой области разрешен только один поток с использованием этого ресурса и т. Д.

Как их использовать, зависит от языка, но часто (если не всегда) основывается на мьютексе операционной системы.

Некоторые языки не нуждаются в этой конструкции из-за парадигмы, например, функционального программирования (хорошие примеры - Haskell, ML).

Матс Фредрикссон
источник
26

В 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;
    }
}

Оператор lock, использующий объект private lock, создает критический раздел. Требование к каждому потоку дождаться окончания предыдущего. Первый поток войдет в раздел и инициализирует экземпляр. Второй поток будет ждать, попасть в раздел и получить инициализированный экземпляр.

Любой вид синхронизации статического члена может использовать оператор блокировки аналогично.

Энтони Мастреан
источник
1
Это зависимый от реализации ответ. Кроме того, в CS монитор отличается от mutex. Мониторы имеют механизм синхронизации, но мьютекс просто блокирует объект, пока он больше не нужен. IDK о деталях реализации или семантике C #, но я думаю, что контекст вопроса более широк
marcoslhc
25

Что такое мьютекс ?

Мьютекс (фактически термин мьютекс - это сокращение от взаимного исключения), также известный как спин-блокировка, является самым простым инструментом синхронизации, который используется для защиты критических областей и, таким образом, предотвращения условий гонки. То есть поток должен получить блокировку перед входом в критический раздел (в критическом разделе несколько потоков совместно используют общую переменную, обновление таблицы, запись файла и т. Д.), Он снимает блокировку, когда покидает критический раздел.

Что такое состояние гонки ?

Состояние гонки возникает, когда два или более потоков могут получить доступ к общим данным, и они пытаются изменить их одновременно. Поскольку алгоритм планирования потоков может переключаться между потоками в любое время, вы не знаете порядок, в котором потоки будут пытаться получить доступ к общим данным. Следовательно, результат изменения данных зависит от алгоритма планирования потоков, то есть оба потока «участвуют в гонке», чтобы получить доступ / изменить данные.

Пример из реальной жизни:

Когда на работе я веду бурную дискуссию, я использую резинового цыпленка, которого держу в своем столе именно для таких случаев. Человек, держащий курицу, является единственным человеком, которому разрешено говорить. Если вы не держите курицу, вы не можете говорить. Вы можете только указать, что хотите курицу, и подождать, пока вы ее получите, прежде чем говорить. Как только вы закончите говорить, вы можете вернуть курицу модератору, который передаст ее следующему человеку, который будет говорить. Это гарантирует, что люди не разговаривают друг с другом, а также имеют свое собственное пространство для общения.

Замените Цыпленка на Мьютекс, а человека - на нить, и у вас в основном будет концепция мьютекса.

@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

MSDN Reference Mutex

хабиб
источник
1
очень хороший пример
Siwei Shen 申思维
22

Здесь есть несколько отличных ответов, вот еще одна замечательная аналогия для объяснения того, что такое мьютекс :

Рассмотрим один туалет с ключом . Когда кто-то входит, они берут ключ и туалет занят . Если кому-то еще нужно пользоваться туалетом, ему нужно ждать в очереди . Когда человек в туалете сделан , он передает ключ следующему человеку в очереди. Имеет смысл, верно?

Преобразуйте туалет в истории в общий ресурс и ключ к мьютексу . Взяв ключ от туалета (приобретите замок), вы сможете его использовать. Если ключа нет (замок заблокирован), вам придется подождать. Когда ключ возвращается человеком ( снимите блокировку ), вы можете получить его сейчас.

Чен А.
источник
Но пример c # не поддерживает поддержку вашего утверждения очереди, «передать ключ следующему человеку в очереди». Пример демонстрирует стек или случайный. 1, 2 и 3 все запрашивают доступ в этой последовательности. Один разрешен в охраняемой зоне, а затем три допускается. Очередь дала бы это второму.
Donvnielsen
Я не имел в виду какую-либо конкретную реализацию или конкретный язык программирования. Мой пример относится к высокоуровневой абстракции мьютекса как принципа.
Чен А.
18

Чтобы понять MUTEX, сначала вам нужно знать, что такое «состояние гонки», и только тогда вы поймете, зачем нужен MUTEX. Предположим, у вас есть многопоточная программа и два потока. Теперь у вас есть одна работа в очереди. Первый поток проверит очередь заданий и, найдя задание, начнет ее выполнять. Второй поток также проверит очередь заданий и обнаружит, что в очереди есть одно задание. Таким образом, он также назначит тот же указатель задания. Итак, что теперь происходит, оба потока выполняют одну и ту же работу. Это приведет к ошибке сегментации. Это пример состояния гонки.

Решением этой проблемы является MUTEX. MUTEX - это своего рода блокировка, которая блокирует один поток за раз. Если другой поток хочет заблокировать его, он просто блокируется.

Тема MUTEX в этой ссылке на файл PDF действительно стоит прочитать.

user3751012
источник
Под «темой MUTEX» вы подразумевали раздел о семафорах, потому что его примеры - это двоичные семафоры, верно?
Карл Дж
2
хорошо Mutex это просто семафор со значением 1
marcoslhc
Как называется книга той главы, которой вы поделились? Пожалуйста
Омар Фарук Аник
@OmarFaroqueAnik Книга, на которую ссылаются, - это Advanced Linux Programming от CodeSourcery LLC, опубликованная New Riders Publishing и доступ к которой можно получить с домашней страницы связанного домена.
RMart
11

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

18hrs
источник
Это действительно так? Разве отдельные процессы не создают свою собственную копию мьютекса?
Леон
0

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.

Это гарантирует, что никакие два процесса / потока не могут получить доступ к критическому разделу одновременно.

Sandeep_black
источник