¿Qué es un mutex?

655

Un mutex es un concepto de programación que se usa con frecuencia para resolver problemas de subprocesos múltiples. Mi pregunta a la comunidad:

¿Qué es un mutex y cómo se usa?

bmurphy1976
fuente
2
Aquí hay un buen artículo sobre la diferencia: barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore
Adam Davis
Un tutorial sobre mutex puede ayudar a aclarar las cosas: stackoverflow.com/questions/4989451/mutex-example-tutorial
Nav
1
Un mutex es como una llave del baño en una estación de servicio, asegurando que solo una persona pueda usar el baño a la vez Y que nadie más pueda usar el inodoro hasta que el ocupante actual haya terminado y la llave sea devuelta.
jonschlinkert

Respuestas:

2154

Cuando estoy teniendo una gran discusión en el trabajo, uso un pollo de goma que guardo en mi escritorio para esas ocasiones. La persona que sostiene el pollo es la única persona a la que se le permite hablar. Si no sostienes el pollo no puedes hablar. Solo puedes indicar que quieres el pollo y esperar hasta que lo consigas antes de hablar. Una vez que haya terminado de hablar, puede devolver el pollo al moderador, que lo entregará a la siguiente persona para que hable. Esto garantiza que las personas no hablen entre sí y que también tengan su propio espacio para hablar.

Reemplaza Chicken con Mutex y person con thread y básicamente tienes el concepto de mutex.

Por supuesto, no existe un mutex de goma. Solo pollo de goma. Mis gatos una vez tuvieron un ratón de goma, pero se lo comieron.

Por supuesto, antes de usar el pollo de goma, debe preguntarse si realmente necesita 5 personas en una habitación y no sería más fácil con una sola persona en la habitación haciendo todo el trabajo. En realidad, esto solo está ampliando la analogía, pero se entiende la idea.

Xetius
fuente
99
Gran respuesta. ¿Podría argumentarse que el Mutex es en realidad las reglas que impiden que se pase el pollo? y el pollo es lo que estás cerrando?
SirYakalot
3
@SirYakalot, ¿quieres decir que el pollo es el recurso y el moderador es el mutex?
Owen
158
El pollo es el mutex . Las personas que construyen el mu .. pollo son hilos competidores . El moderador es el sistema operativo . Cuando las personas solicitan el pollo, hacen una solicitud de bloqueo. Cuando llama a mutex.lock (), su hilo se detiene en lock () y realiza una solicitud de bloqueo al sistema operativo. Cuando el sistema operativo detecta que el mutex se liberó de un hilo, simplemente se lo da a usted y lock () regresa: el mutex ahora es suyo y solo suyo. Nadie más puede robarlo, porque llamar a lock () lo bloqueará. También hay try_lock () que bloqueará y devolverá verdadero cuando mutex es suyo e inmediatamente falso si mutex está en uso.
Петър Петров
44
Eres un genio. ¿Puedes usar también la metáfora del pollo de goma para explicar los monitores?
Riccardo
98
A veces, el origen de algunos conceptos de programación no está claro. Un novato podría preguntarse por qué todos están hablando de expresiones regulares. No es evidente que regex sea la abreviatura de [regular] [ex] presión. Del mismo modo, mutex es la abreviatura de [mut] ual [ex] clusion. Esto podría hacer que el significado del término sea más fácil de digerir. @TheSmurf lo vinculó en su respuesta, pero podría ser bueno agregarlo aquí con fines históricos.
Dodzi Dzakuma
138

Un Mutex es una bandera mutuamente excluyente. Actúa como un guardián de puerta a una sección de código que permite un hilo y bloquea el acceso a todos los demás. Esto garantiza que el código que se controla solo sea alcanzado por un solo hilo a la vez. Solo asegúrese de liberar el mutex cuando haya terminado. :)

Craig
fuente
11
Un mutex no tiene nada que ver con una sección de código per se, protege algunos recursos. Ese recurso puede ser un segmento de código si el mutex solo se usa alrededor de ese código pero, en el momento en que comienza a usar el mutex en varios lugares de su código, su explicación falla. Por lo general, también se puede usar para proteger cierta estructura de datos, a la que se puede acceder desde muchos lugares del código.
paxdiablo
73

Exclusión mutua. Aquí está la entrada de Wikipedia:

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

El objetivo de un mutex es sincronizar dos hilos. Cuando tiene dos hilos que intentan acceder a un solo recurso, el patrón general es tener el primer bloque de código que intenta acceder para establecer el mutex antes de ingresar el código. Cuando el segundo bloque de código intenta acceder, ve que el mutex está configurado y espera hasta que se complete el primer bloque de código (y desarma el mutex), luego continúa.

Los detalles específicos de cómo se logra esto obviamente varían mucho según el lenguaje de programación.

El Pitufo
fuente
65

Cuando tiene una aplicación multiproceso, los diferentes subprocesos a veces comparten un recurso común, como una variable o similar. A menudo no se puede acceder a esta fuente compartida al mismo tiempo, por lo que se necesita una construcción para garantizar que solo un subproceso esté usando ese recurso a la vez.

El concepto se llama "exclusión mutua" (Mutex corto) y es una forma de garantizar que solo se permita un subproceso dentro de esa área, utilizando ese recurso, etc.

La forma de usarlos es específica del idioma, pero a menudo (si no siempre) se basa en un mutex del sistema operativo.

Algunos lenguajes no necesitan esta construcción, debido al paradigma, por ejemplo, la programación funcional (Haskell, ML son buenos ejemplos).

Mats Fredriksson
fuente
26

En C #, el mutex común utilizado es el Monitor . El tipo es ' System.Threading.Monitor '. También se puede usar implícitamente a través de la declaración ' lock (Object) '. Un ejemplo de su uso es cuando se construye una clase 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;
    }
}

La declaración de bloqueo que usa el objeto de bloqueo privado crea una sección crítica. Requerir que cada hilo espere hasta que finalice el anterior. El primer hilo entrará en la sección e inicializará la instancia. El segundo subproceso esperará, entrará en la sección y obtendrá la instancia inicializada.

Cualquier tipo de sincronización de un miembro estático puede usar la declaración de bloqueo de manera similar.

Anthony Mastrean
fuente
1
Esta es una respuesta dependiente de la implementación. Además, en CS un monitor es diferente a mutex. Los monitores tienen un mecanismo de sincronización, pero mutex simplemente bloquea la cosa hasta que ya no sea necesaria. IDK sobre detalles de implementación o semántica de C #, pero creo que el contexto de la pregunta es más amplio
marcoslhc
25

¿Qué es un mutex ?

El mutex (de hecho, el término mutex es la abreviatura de exclusión mutua), también conocido como spinlock, es la herramienta de sincronización más simple que se utiliza para proteger las regiones críticas y evitar así las condiciones de carrera. Es decir, un subproceso debe adquirir un bloqueo antes de entrar en una sección crítica (en la sección crítica, varios subprocesos comparten una variable común, actualizar una tabla, escribir un archivo, etc.), libera el bloqueo cuando sale de la sección crítica.

¿Qué es una condición de carrera ?

Una condición de carrera ocurre cuando dos o más subprocesos pueden acceder a datos compartidos e intentan cambiarlos al mismo tiempo. Debido a que el algoritmo de programación de subprocesos puede intercambiar entre subprocesos en cualquier momento, no conoce el orden en que los subprocesos intentarán acceder a los datos compartidos. Por lo tanto, el resultado del cambio en los datos depende del algoritmo de programación de subprocesos, es decir, ambos subprocesos "compiten" para acceder / cambiar los datos.

Ejemplo de la vida real:

Cuando estoy teniendo una gran discusión en el trabajo, uso un pollo de goma que guardo en mi escritorio para esas ocasiones. La persona que sostiene el pollo es la única persona a la que se le permite hablar. Si no sostienes el pollo no puedes hablar. Solo puedes indicar que quieres el pollo y esperar hasta que lo consigas antes de hablar. Una vez que haya terminado de hablar, puede devolver el pollo al moderador, que lo entregará a la siguiente persona para que hable. Esto garantiza que las personas no hablen entre sí y que también tengan su propio espacio para hablar.

Reemplaza Chicken con Mutex y person con thread y básicamente tienes el concepto de mutex.

@Xetius

Uso en C #:

Este ejemplo muestra cómo se usa un objeto Mutex local para sincronizar el acceso a un recurso protegido. Debido a que cada subproceso de llamada se bloquea hasta que adquiere la propiedad del mutex, debe llamar al método ReleaseMutex para liberar la propiedad del subproceso.

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 Referencia Mutex

habib
fuente
1
un muy buen ejemplo
Siwei Shen
22

Aquí hay algunas respuestas excelentes, aquí hay otra gran analogía para explicar qué es mutex :

Considere inodoro individual con llave . Cuando alguien entra, toman la llave y el baño está ocupado . Si alguien más necesita usar el baño, debe esperar en la cola . Cuando la persona en el baño termina , le pasan la llave a la siguiente persona en la cola. Tiene sentido, ¿verdad?

Convierta el inodoro en la historia en un recurso compartido y la clave en un mutex . Llevar la llave al baño (adquirir una cerradura) le permite usarla. Si no hay llave (la cerradura está bloqueada) debe esperar. Cuando la persona devuelve la llave ( suelta la cerradura ), ahora puedes adquirirla.

Chen A.
fuente
Pero el ejemplo de c # no admite la afirmación de la cola, "pasa la clave a la siguiente persona en la cola". El ejemplo está demostrando una pila o al azar. 1, 2 y 3 solicitan acceso, en esa secuencia. Primero se permite que uno entre al área protegida, y luego se permite tres. Una cola lo habría dado a la segunda.
donvnielsen
No me refería a ninguna implementación concreta ni a un lenguaje de programación concreto. Mi ejemplo se refiere a la abstracción de alto nivel de mutex como principio.
Chen A.
18

Para comprender MUTEX al principio, necesita saber qué es la "condición de carrera" y luego solo usted comprenderá por qué se necesita MUTEX. Supongamos que tiene un programa de subprocesos múltiples y tiene dos subprocesos. Ahora, tiene un trabajo en la cola de trabajos. El primer hilo verificará la cola de trabajos y después de encontrar el trabajo comenzará a ejecutarlo. El segundo subproceso también verificará la cola de trabajos y encontrará que hay un trabajo en la cola. Por lo tanto, también asignará el mismo puntero de trabajo. Entonces, ahora que sucede, ambos hilos están ejecutando el mismo trabajo. Esto causará una falla de segmentación. Este es el ejemplo de una condición de carrera.

La solución a este problema es MUTEX. MUTEX es un tipo de bloqueo que bloquea un hilo a la vez. Si otro hilo quiere bloquearlo, el hilo simplemente se bloquea.

El tema de MUTEX en este enlace de archivo pdf realmente vale la pena leer.

usuario3751012
fuente
Por "tema MUTEX" se refería a la sección sobre semáforos, porque sus ejemplos son de semáforos binarios, ¿verdad?
Carl G
2
bueno, un Mutex es solo un semáforo con valor 1
marcoslhc
¿Cuál es el nombre del libro de ese capítulo que compartiste? Por favor
Omar Faroque Anik
@OmarFaroqueAnik, el libro al que se hace referencia es Advanced Linux Programming de CodeSourcery LLC, publicado por New Riders Publishing y se puede acceder desde la página de inicio del dominio vinculado.
RMart
11

Los mutexes son útiles en situaciones en las que necesita forzar el acceso exclusivo a un recurso a través de múltiples procesos, donde un bloqueo regular no ayudará, ya que solo funciona a través de subprocesos.

18 horas
fuente
¿Es eso realmente cierto? ¿Los procesos individuales no crearán su propia copia mutex?
Leon
0

Mutex: mutex significa Mut UAL Ex conclusión. Significa que a la vez un proceso / hilo puede entrar en la sección crítica. En la programación concurrente en la que múltiples subprocesos / procesos intentan actualizar el recurso compartido (cualquier variable, memoria compartida, etc.) puede generar algún resultado inesperado. (Como el resultado depende del hilo / proceso que obtiene el primer acceso).

Para evitar un resultado tan inesperado, necesitamos un mecanismo de sincronización, que garantice que solo un subproceso / proceso tenga acceso a dicho recurso a la vez.

La biblioteca pthread proporciona soporte para 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

Esta es la estructura para el tipo de datos mutex, es decir, pthread_mutex_t. Cuando mutex está bloqueado, __lock está establecido en 1. Cuando está desbloqueado, __lock está establecido en 0.

Esto garantiza que no haya dos procesos / subprocesos que puedan acceder a la sección crítica al mismo tiempo.

Sandeep_black
fuente