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 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?
Risposte:
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.
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. :)
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.
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).
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.
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
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.
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.
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.