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

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

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


person bmurphy1976    schedule 29.08.2008    source источник
comment
Вот хорошая статья о различиях: barrgroup.com/Embedded- Системы / Инструкции / RTOS-Mutex-Semaphore   -  person Adam Davis    schedule 15.04.2015
comment
Учебник по мьютексу может помочь прояснить ситуацию: stackoverflow.com/questions/4989451/mutex -example-tutorial   -  person Nav    schedule 05.05.2018
comment
Мьютекс похож на ключ от ванной на заправочной станции, гарантируя, что только один человек может пользоваться ванной одновременно, И что никто другой не может пользоваться туалетом, пока текущий житель не закончит и ключ не будет возвращен.   -  person jonschlinkert    schedule 02.01.2020


Ответы (10)


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

Замените Chicken на Mutex и person на thread, и вы получите концепцию мьютекса.

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

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

person Xetius    schedule 29.08.2008
comment
@SirYakalot, вы про курицу это ресурс, а модератор мьютекс? - person Owen; 09.10.2012
comment
Курица - это мьютекс. Люди, держащие мю .. цыпленка, - конкурирующие темы. Модератором является ОС. Когда люди запрашивают курицу, они делают запрос на блокировку. Когда вы вызываете mutex.lock (), ваш поток останавливается в lock () и делает запрос на блокировку в ОС. Когда ОС обнаруживает, что мьютекс был выпущен из потока, она просто передает его вам, а функция lock () возвращает значение - теперь мьютекс принадлежит вам и только вам. Никто другой не может его украсть, потому что вызов lock () заблокирует его. Также существует функция try_lock (), которая будет блокировать и возвращать true, если мьютекс принадлежит вам, и сразу же false, если мьютекс используется. - person Петър Петров; 22.09.2014
comment
Иногда происхождение некоторых концепций программирования неясно. Новичок может удивиться, почему все говорят о регулярных выражениях. Не очевидно, что регулярное выражение является сокращением от [регулярного] [выражения]. Точно так же мьютекс - это сокращение от [mut] ual [ex] clusion ». Это может облегчить усвоение значения термина. @TheSmurf связался с ним в своем ответе, но было бы неплохо добавить его здесь для исторических целей. - person Dodzi Dzakuma; 10.12.2015
comment
Кто-то читал "Повелителя мух" :-) RubberChicken == Conch sparknotes.com/lit/flies/central-idea-essay/ - person Cerniuk; 21.11.2019
comment
Конечно, резиновых мьютексов не существует. Спасибо за разъяснение. - person ACV; 21.07.2020
comment
@Xetius, можете ли вы включить комментарий Петър Петрова к вашему ответу? Это сделает ваш ответ более полным ... - person Sabito 錆兎; 27.08.2020
comment
Лучший ответ, который я когда-либо видел в stackoverflow, элегантный. - person mediumnok; 29.05.2021
comment
Не путайте с отладкой «резиновая утка». - person MC Emperor; 13.07.2021

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

person Craig    schedule 29.08.2008
comment
Мьютекс не имеет ничего общего с частью кода как таковой, он защищает некоторый ресурс. Этот ресурс может быть сегментом кода, если мьютекс когда-либо используется только вокруг этого кода, но в ту минуту, когда вы начинаете использовать мьютекс в нескольких местах вашего кода, ваше объяснение не работает. Обычно его также можно использовать для защиты некоторой структуры данных, к которой можно получить доступ из многих мест в коде. - person paxdiablo; 22.11.2017
comment
@paxdiablo: позвольте мне не согласиться. У вас может быть 2 фрагмента кода: один использует Mutex, а другой нет. Вы получаете доступ к структуре данных из обоих фрагментов кода. Как Mutex защищает структуру данных? Это не так. У вас будет гонка данных, как если бы Mutex вообще не было. - person Thomas Weller; 16.02.2021
comment
@Thomas, значит, в вашем коде есть ошибка. Сказать, что мьютекс не защищает данные, потому что вы не используете мьютекс в одной из необходимых вам точек, не отличается от того, чтобы сказать, что ваша домашняя безопасность недостаточна, потому что по четвергам вы оставляете входную дверь незапертой и открываете, когда ты идешь на работу :-) - person paxdiablo; 17.02.2021
comment
@paxdiablo: вот моя точка зрения: разработчик должен следовать соглашению, согласно которому он получает доступ к структуре данных только с помощью кода, который защищен Mutex. Mutex защищает код. Он не защищает структуру данных. Я бы сказал, что безопасность моего дома бесполезна, если я регулярно оставляю дверь открытой. Затем я реализовал это неправильно, как будто я неправильно реализовал код. - person Thomas Weller; 17.02.2021
comment
@ Томас, я подозреваю, что дело в семантике. На мой взгляд, забвение использовать мьютекс для защиты данных ничем не отличается от того, что забывают использовать его для защиты кода. В какой-то момент вы забыли защитить его, это повлечет за собой веселье :-) Я вижу вашу точку зрения, но я должен придерживаться своего описания, потому что обычно нет никаких проблем с несколькими потоками, выполняющими один и тот же код , поскольку сам код под ними не меняется. Проблемы могут возникнуть только тогда, когда данные изменятся неожиданно. - person paxdiablo; 17.02.2021
comment
В любом случае, не очень хочу засорять ответ Крейга дополнительными комментариями, я оставлю все как есть :-) - person paxdiablo; 17.02.2021

Mut ual Ex clusion. Вот запись об этом в Википедии.

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

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

person TheSmurf    schedule 29.08.2008

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

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

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

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

person Mats Fredriksson    schedule 29.08.2008

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

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

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

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

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

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

Замените 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

Справочный мьютекс MSDN

person habib    schedule 03.07.2018
comment
Как же реализован Mutex? Это аппаратное обеспечение? Есть ли у него какой-то механизм ожидания, чтобы убедиться, что все потоки знают текущее состояние? - person android developer; 02.04.2021

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

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

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

person Chen A.    schedule 09.10.2017
comment
Но пример C # не поддерживает утверждение вашей очереди, передайте ключ следующему человеку в очереди. Пример демонстрирует стек или случайный. 1, 2 и 3 все запрашивают доступ в этой последовательности. Сначала разрешается войти в охраняемую зону, а затем - троим. Очередь отдала бы его второму. - person donvnielsen; 27.12.2019
comment
Я не имел в виду конкретную реализацию или конкретный язык программирования. Мой пример относится к высокоуровневой абстракции мьютексов как принципа. - person Chen A.; 27.12.2019

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

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

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

person Anthony Mastrean    schedule 29.08.2008
comment
Это зависит от реализации. Кроме того, в CS монитор отличается от мьютекса. Мониторы имеют механизм синхронизации, но мьютекс просто блокирует объект до тех пор, пока он больше не понадобится. IDK о деталях реализации или семантике C #, но я думаю, что контекст вопроса шире - person marcoslhc; 03.10.2015

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

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

Ссылка на тему MUTEX в этом pdf-файле действительно заслуживает внимания.

person user3751012    schedule 27.06.2014
comment
Под темой MUTEX вы имели в виду раздел семафоров, потому что это примеры двоичных семафоров, верно? - person Carl G; 09.12.2014
comment
ну, мьютекс - это просто семафор со значением 1 - person marcoslhc; 03.10.2015
comment
Как называется книга той главы, которой вы поделились? Пожалуйста - person Omar Faroque Anik; 27.02.2017
comment
@OmarFaroqueAnik, на которую ссылается книга, - Advanced Linux Programming by CodeSourcery LLC, опубликованная New Riders Publishing, доступ к которой можно получить с домашней страницы связанного домена. - person RMart; 01.03.2017
comment
Чтобы сначала понять ошибку сегментации, вам нужно знать, что такое ... - person Schrodo_Baggins; 03.09.2020

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

person 18hrs    schedule 02.09.2008
comment
Это действительно так? Разве отдельные процессы не создают свою собственную копию мьютекса? - person Leon; 08.04.2015

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.

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

person Sandeep_black    schedule 23.01.2020