Che cos'è un mutex?


655

Un mutex è un concetto di programmazione che viene spesso utilizzato per risolvere problemi multi-threading. La mia domanda alla comunità:

Che cos'è un mutex e come lo usi?



Un tutorial su mutex può aiutare a chiarire le cose: stackoverflow.com/questions/4989451/mutex-example-tutorial
Nav

1
Un mutex è come una chiave del bagno in una stazione di servizio, assicurando che solo una persona alla volta possa usare il bagno E che nessun altro possa usare il bagno fino a quando l'occupante attuale non ha finito e la chiave viene restituita.
jonschlinkert,

Risposte:


2154

Quando sto avendo una grande discussione accesa sul lavoro, uso un pollo di gomma che tengo nella mia scrivania proprio per queste occasioni. La persona che tiene il pollo è l'unica persona a cui è permesso parlare. Se non tieni il pollo non puoi parlare. Puoi solo indicare che vuoi il pollo e aspettare fino a quando non lo prendi prima di parlare. Una volta che hai finito di parlare, puoi restituire il pollo al moderatore che lo consegnerà alla persona successiva per parlare. Questo assicura che le persone non parlino l'una sull'altra e abbiano anche il loro spazio per parlare.

Sostituisci Chicken con Mutex e persona con thread e fondamentalmente hai il concetto di mutex.

Certo, non esiste un mutex di gomma. Solo pollo di gomma. I miei gatti una volta avevano un topo di gomma, ma lo mangiavano.

Naturalmente, prima di usare il pollo di gomma, devi chiederti se in realtà hai bisogno di 5 persone in una stanza e non sarebbe solo più facile con una persona nella stanza da sola fare tutto il lavoro. In realtà, questo sta solo estendendo l'analogia, ma ottieni l'idea.


9
Bella risposta. Si potrebbe sostenere che il Mutex è in realtà le regole che impediscono il passaggio del pollo? e il pollo è la cosa che stai bloccando?
SirYakalot,

3
@SirYakalot, vuoi dire che il pollo è la risorsa e il moderatore è il mutex?
Owen,

157
Il pollo è il mutex . Le persone che allevano il pollo .. sono fili in competizione . Il moderatore è il sistema operativo . Quando le persone richiedono il pollo, fanno una richiesta di blocco. Quando chiami mutex.lock (), il thread si blocca in lock () e invia una richiesta di blocco al sistema operativo. Quando il sistema operativo rileva che il mutex è stato rilasciato da un thread, lo dà semplicemente a te e il blocco () ritorna - il mutex è ora tuo e solo tuo. Nessun altro può rubarlo, perché chiamare lock () lo bloccherà. C'è anche try_lock () che bloccherà e restituirà true quando mutex è tuo e immediatamente false se mutex è in uso.
Петър Петров

4
Sei un genio. Puoi usare anche la metafora del pollo in gomma per spiegare i monitor?
Riccardo

98
A volte l'origine di alcuni concetti di programmazione non è chiara. Un principiante potrebbe andare in giro chiedendosi perché tutti parlano di regex. Non è chiaro che regex sia l'abbreviazione di [reg] ular [ex] pression. Allo stesso modo, mutex è l'abbreviazione di [mut] ual [ex] clusion. Ciò potrebbe rendere il significato del termine più facile da digerire. @TheSmurf si è collegato ad esso nella loro risposta, ma potrebbe essere utile aggiungerlo qui per scopi storici.
Dodzi Dzakuma,

138

Un Mutex è una bandiera che si esclude a vicenda. Funge da gate keeper per una sezione di codice che consente un thread in entrata e blocca l'accesso a tutti gli altri. Ciò garantisce che il codice da controllare verrà colpito solo da un singolo thread alla volta. Assicurati di rilasciare il mutex quando hai finito. :)


11
Un mutex non ha nulla a che fare con una sezione di codice in sé, protegge alcune risorse. Quella risorsa può essere un segmento di codice se il mutex viene usato solo intorno a quel codice ma, nel momento in cui inizi a utilizzare il mutex in più punti del codice, la tua spiegazione fallisce. In genere può anche essere utilizzato per proteggere alcune strutture di dati, a cui è possibile accedere da molti punti del codice.
paxdiablo,

73

Esclusione reciproca. Ecco la voce di Wikipedia su di esso:

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

Il punto di un mutex è sincronizzare due thread. Quando due thread tentano di accedere a una singola risorsa, il modello generale prevede che il primo blocco di codice tenti di accedere per impostare il mutex prima di immettere il codice. Quando il secondo blocco di codice tenta di accedere, vede il mutex impostato e attende fino al completamento del primo blocco di codice (e disattiva il mutex), quindi continua.

I dettagli specifici di come ciò avviene ovviamente variano notevolmente a seconda del linguaggio di programmazione.


65

Quando si dispone di un'applicazione multi-thread, i diversi thread a volte condividono una risorsa comune, come una variabile o simile. A questa fonte condivisa spesso non è possibile accedere contemporaneamente, quindi è necessario un costrutto per garantire che un solo thread stia utilizzando quella risorsa alla volta.

Il concetto si chiama "mutua esclusione" (breve Mutex) ed è un modo per garantire che un solo thread sia consentito all'interno di quell'area, usando quella risorsa ecc.

Come usarli è specifico della lingua, ma spesso (se non sempre) si basa su un mutex del sistema operativo.

Alcuni linguaggi non hanno bisogno di questo costrutto, a causa del paradigma, ad esempio la programmazione funzionale (Haskell, ML sono buoni esempi).


26

In C #, il mutex comune utilizzato è il monitor . Il tipo è " System.Threading.Monitor ". Può anche essere usato implicitamente tramite l' istruzione ' lock (Object) '. Un esempio del suo utilizzo è quando si costruisce una classe 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;
    }
}

L'istruzione lock usando l'oggetto lock privato crea una sezione critica. Richiede ad ogni thread di attendere fino al termine del precedente. Il primo thread entrerà nella sezione e inizializzerà l'istanza. Il secondo thread attenderà, entrerà nella sezione e otterrà l'istanza inizializzata.

Qualsiasi tipo di sincronizzazione di un membro statico può utilizzare l'istruzione lock in modo simile.


1
Questa è una risposta dipendente dall'implementazione. Inoltre, in CS un monitor è diverso da mutex. I monitor hanno un meccanismo di sincronizzazione, ma il mutex blocca la cosa fino a quando non è più necessario. IDK sui dettagli di implementazione o semantica C #, ma penso che il contesto della domanda sia più ampio
marcoslhc,

25

Che cos'è un Mutex ?

Il mutex (in effetti, il termine mutex è l'abbreviazione di mutua esclusione) noto anche come spinlock è lo strumento di sincronizzazione più semplice che viene utilizzato per proteggere le regioni critiche e quindi prevenire le condizioni di gara. Cioè un thread deve acquisire un blocco prima di entrare in una sezione critica (nella sezione critica più thread condividono una variabile comune, aggiornando una tabella, scrivendo un file e così via), rilascia il blocco quando lascia la sezione critica.

Che cos'è una condizione di gara ?

Una condizione di competizione si verifica quando due o più thread possono accedere ai dati condivisi e tentano di modificarli contemporaneamente. Poiché l'algoritmo di pianificazione dei thread può passare da un thread all'altro in qualsiasi momento, non si conosce l'ordine in cui i thread tenteranno di accedere ai dati condivisi. Pertanto, il risultato della modifica dei dati dipende dall'algoritmo di pianificazione dei thread, ovvero entrambi i thread stanno "correndo" per accedere / modificare i dati.

Esempio di vita reale:

Quando sto avendo una grande discussione accesa sul lavoro, uso un pollo di gomma che tengo nella mia scrivania proprio per queste occasioni. La persona che tiene il pollo è l'unica persona a cui è permesso parlare. Se non tieni il pollo non puoi parlare. Puoi solo indicare che vuoi il pollo e aspettare fino a quando non lo prendi prima di parlare. Una volta che hai finito di parlare, puoi restituire il pollo al moderatore che lo consegnerà alla persona successiva per parlare. Questo assicura che le persone non parlino l'una sull'altra e abbiano anche il loro spazio per parlare.

Sostituisci Chicken con Mutex e persona con thread e fondamentalmente hai il concetto di mutex.

@Xetius

Utilizzo in C #:

Questo esempio mostra come un oggetto Mutex locale viene utilizzato per sincronizzare l'accesso a una risorsa protetta. Poiché ogni thread chiamante viene bloccato fino a quando non acquisisce la proprietà del mutex, è necessario chiamare il metodo ReleaseMutex per rilasciare la proprietà del thread.

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 di riferimento MSDN


1
un ottimo esempio
Siwei Shen 申思维

22

Ci sono alcune grandi risposte qui, ecco un'altra grande analogia per spiegare cos'è il mutex :

Prendi in considerazione la toilette singola con una chiave . Quando qualcuno entra, prendono la chiave e il bagno è occupato . Se qualcun altro ha bisogno di usare il bagno, deve attendere in coda . Quando la persona nella toilette ha finito , passa la chiave alla persona successiva in coda. Ha senso, vero?

Converti la toilette nella storia in una risorsa condivisa e la chiave per un mutex . Portare la chiave in bagno (acquisire una serratura) ti consente di usarla. Se non è presente alcuna chiave (il blocco è bloccato), è necessario attendere. Quando la chiave viene restituita dalla persona ( rilascia il lucchetto ) sei libero di acquisirla ora.


Ma l'esempio c # non supporta l'asserzione della coda "passa la chiave alla persona successiva in coda". L'esempio sta dimostrando uno stack o casuale. 1, 2 e 3 richiedono tutti l'accesso, in quella sequenza. Uno è prima consentito nell'area protetta, quindi tre sono consentiti. Una coda l'avrebbe assegnata alla seconda.
donvnielsen,

Non mi riferivo a nessuna implementazione concreta o linguaggio di programmazione concreto. Il mio esempio riguarda l'astrazione di alto livello del mutex come principio.
Chen A.

18

Per capire inizialmente MUTEX devi sapere che cos'è la "condizione di gara" e solo allora capirai perché MUTEX è necessario. Supponiamo di avere un programma multi-threading e di avere due thread. Ora, hai un lavoro in coda. Il primo thread controllerà la coda dei lavori e dopo aver trovato il lavoro inizierà l'esecuzione. Il secondo thread controllerà anche la coda dei lavori e scoprirà che esiste un lavoro nella coda. Quindi, assegnerà anche lo stesso puntatore lavoro. Quindi, ora cosa succede, entrambi i thread stanno eseguendo lo stesso lavoro. Ciò causerà un errore di segmentazione. Questo è l'esempio di una condizione di gara.

La soluzione a questo problema è MUTEX. MUTEX è un tipo di blocco che blocca un thread alla volta. Se un altro thread vuole bloccarlo, il thread viene semplicemente bloccato.

L'argomento MUTEX in questo link al file pdf merita davvero di essere letto.


Per "argomento MUTEX" intendevi la sezione sui semafori, perché i suoi esempi sono di semafori binari, giusto?
Carl G,

2
bene un Mutex è solo un semaforo con valore 1
marcoslhc

Qual è il nome del libro di quel capitolo che hai condiviso? Per favore
Omar Faroque Anik,

@OmarFaroqueAnik il libro cui si fa riferimento è Advanced Linux Programming di CodeSourcery LLC, pubblicato da New Riders Publishing e accessibile dalla home page del dominio collegato.
RM

11

I mutex sono utili nelle situazioni in cui è necessario imporre l'accesso esclusivo a una risorsa attraverso più processi, in cui un blocco regolare non aiuta poiché funziona solo attraverso i thread.


È davvero vero? I singoli processi non creano la propria copia di mutex?
Leon,

0

Mutex: Mutex è l'acronimo di Mut ual Ex clusion. Significa che in un momento un processo / thread può entrare nella sezione critica. Nella programmazione concorrente in cui più thread / processi tentano di aggiornare la risorsa condivisa (qualsiasi variabile, memoria condivisa ecc.) Può portare a risultati imprevisti. (Poiché il risultato dipende dal thread / processo che ottiene il primo accesso).

Per evitare un risultato così inaspettato, abbiamo bisogno di un meccanismo di sincronizzazione, che assicuri che solo un thread / processo abbia accesso a tale risorsa alla volta.

La libreria pthread fornisce supporto per 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

Questa è la struttura per il tipo di dati mutex, ad esempio pthread_mutex_t. Quando mutex è bloccato, __lock impostato su 1. Quando è sbloccato __lock impostato su 0.

Ciò garantisce che nessun processo / thread possa accedere alla sezione critica contemporaneamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.