Ein Mutex ist ein Programmierkonzept, das häufig zur Lösung von Multithreading-Problemen verwendet wird. Meine Frage an die Community:
Was ist ein Mutex und wie benutzt man ihn?
Ein Mutex ist ein Programmierkonzept, das häufig zur Lösung von Multithreading-Problemen verwendet wird. Meine Frage an die Community:
Was ist ein Mutex und wie benutzt man ihn?
Antworten:
Wenn ich bei der Arbeit eine große hitzige Diskussion habe, benutze ich ein Gummihuhn, das ich für solche Gelegenheiten in meinem Schreibtisch aufbewahre. Die Person, die das Huhn hält, ist die einzige Person, die sprechen darf. Wenn Sie das Huhn nicht halten, können Sie nicht sprechen. Sie können nur angeben, dass Sie das Huhn möchten, und warten, bis Sie es erhalten, bevor Sie sprechen. Sobald Sie mit dem Sprechen fertig sind, können Sie das Huhn dem Moderator zurückgeben, der es der nächsten Person zum Sprechen übergibt. Dies stellt sicher, dass die Menschen nicht über einander sprechen und auch ihren eigenen Raum zum Reden haben.
Ersetzen Sie Huhn durch Mutex und Person durch Faden und Sie haben im Grunde das Konzept eines Mutex.
Natürlich gibt es keinen Gummimutex. Nur Gummihuhn. Meine Katzen hatten einmal eine Gummimaus, aber sie haben sie gegessen.
Bevor Sie das Gummihuhn verwenden, müssen Sie sich natürlich fragen, ob Sie tatsächlich 5 Personen in einem Raum benötigen. Wäre es nicht einfacher, wenn eine Person im Raum die ganze Arbeit alleine erledigt? Eigentlich erweitert dies nur die Analogie, aber Sie bekommen die Idee.
Ein Mutex schließt sich gegenseitig aus. Es fungiert als Gate Keeper für einen Codeabschnitt, der einen Thread zulässt und den Zugriff auf alle anderen blockiert. Dies stellt sicher, dass der zu steuernde Code jeweils nur von einem einzelnen Thread getroffen wird. Stellen Sie einfach sicher, dass Sie den Mutex freigeben, wenn Sie fertig sind. :) :)
Gegenseitiger Ausschluss. Hier ist der Wikipedia-Eintrag dazu:
http://en.wikipedia.org/wiki/Mutual_exclusion
Der Sinn eines Mutex besteht darin, zwei Threads zu synchronisieren. Wenn zwei Threads versuchen, auf eine einzelne Ressource zuzugreifen, besteht das allgemeine Muster darin, dass der erste Codeblock versucht, auf den Mutex zuzugreifen, bevor der Code eingegeben wird. Wenn der zweite Codeblock versucht, darauf zuzugreifen, sieht er, dass der Mutex gesetzt ist, und wartet, bis der erste Codeblock vollständig ist (und setzt den Mutex zurück), und fährt dann fort.
Spezifische Details, wie dies erreicht wird, variieren offensichtlich stark je nach Programmiersprache.
Wenn Sie eine Multithread-Anwendung haben, teilen sich die verschiedenen Threads manchmal eine gemeinsame Ressource, z. B. eine Variable oder ähnliches. Auf diese gemeinsam genutzte Quelle kann häufig nicht gleichzeitig zugegriffen werden. Daher ist ein Konstrukt erforderlich, um sicherzustellen, dass jeweils nur ein Thread diese Ressource verwendet.
Das Konzept wird als "gegenseitiger Ausschluss" (kurzer Mutex) bezeichnet und stellt sicher, dass nur ein Thread in diesem Bereich zulässig ist, der diese Ressource usw. verwendet.
Die Verwendung ist sprachspezifisch, basiert jedoch häufig (wenn nicht immer) auf einem Betriebssystem-Mutex.
Einige Sprachen benötigen dieses Konstrukt aufgrund des Paradigmas nicht, beispielsweise die funktionale Programmierung (Haskell, ML sind gute Beispiele).
In C # verwendet , die gemeinsame Mutex ist der Monitor - . Der Typ ist ' System.Threading.Monitor '. Es kann auch implizit über die Anweisung ' lock (Object) ' verwendet werden. Ein Beispiel für die Verwendung ist das Erstellen einer Singleton-Klasse.
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;
}
}
Die lock-Anweisung, die das private lock-Objekt verwendet, erstellt einen kritischen Abschnitt. Jeder Thread muss warten, bis der vorherige fertig ist. Der erste Thread betritt den Abschnitt und initialisiert die Instanz. Der zweite Thread wartet, gelangt in den Abschnitt und ruft die initialisierte Instanz ab.
Jede Art der Synchronisation eines statischen Elements kann die lock-Anweisung auf ähnliche Weise verwenden.
Was ist ein Mutex ?
Der Mutex (der Begriff Mutex steht für gegenseitigen Ausschluss), auch als Spinlock bezeichnet, ist das einfachste Synchronisationswerkzeug, das zum Schutz kritischer Regionen und damit zur Verhinderung von Rennbedingungen verwendet wird. Das heißt, ein Thread muss eine Sperre erhalten, bevor er in einen kritischen Abschnitt eintritt (in einem kritischen Abschnitt teilen sich mehrere Threads eine gemeinsame Variable, aktualisieren eine Tabelle, schreiben eine Datei usw.) und geben die Sperre frei, wenn er den kritischen Abschnitt verlässt.
Was ist eine Rennbedingung ?
Eine Race-Bedingung tritt auf, wenn zwei oder mehr Threads auf gemeinsam genutzte Daten zugreifen können und gleichzeitig versuchen, diese zu ändern. Da der Thread-Planungsalgorithmus jederzeit zwischen Threads wechseln kann, wissen Sie nicht, in welcher Reihenfolge die Threads versuchen, auf die gemeinsam genutzten Daten zuzugreifen. Daher hängt das Ergebnis der Datenänderung vom Thread-Planungsalgorithmus ab, dh beide Threads "rennen" um auf die Daten zuzugreifen / diese zu ändern.
Beispiel aus dem wirklichen Leben:
Wenn ich bei der Arbeit eine große hitzige Diskussion habe, benutze ich ein Gummihuhn, das ich für solche Gelegenheiten in meinem Schreibtisch aufbewahre. Die Person, die das Huhn hält, ist die einzige Person, die sprechen darf. Wenn Sie das Huhn nicht halten, können Sie nicht sprechen. Sie können nur angeben, dass Sie das Huhn möchten, und warten, bis Sie es erhalten, bevor Sie sprechen. Sobald Sie mit dem Sprechen fertig sind, können Sie das Huhn dem Moderator zurückgeben, der es der nächsten Person zum Sprechen übergibt. Dies stellt sicher, dass die Menschen nicht über einander sprechen und auch ihren eigenen Raum zum Reden haben.
Ersetzen Sie Huhn durch Mutex und Person durch Faden und Sie haben im Grunde das Konzept eines Mutex.
@ Xetius
Verwendung in C #:
Dieses Beispiel zeigt, wie ein lokales Mutex-Objekt verwendet wird, um den Zugriff auf eine geschützte Ressource zu synchronisieren. Da jeder aufrufende Thread blockiert wird, bis er den Besitz des Mutex erlangt, muss er die ReleaseMutex-Methode aufrufen, um den Besitz des Threads freizugeben.
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
Hier gibt es einige großartige Antworten. Hier ist eine weitere großartige Analogie, um zu erklären, was Mutex ist:
Betrachten Sie eine einzelne Toilette mit einem Schlüssel . Wenn jemand hereinkommt, nimmt er den Schlüssel und die Toilette ist besetzt . Wenn jemand anderes die Toilette benutzen muss, muss er in einer Warteschlange warten . Wenn die Person in der Toilette fertig ist , gibt sie den Schlüssel an die nächste Person in der Warteschlange weiter. Sinn machen, oder?
Konvertieren Sie die Toilette in der Geschichte in eine gemeinsame Ressource und den Schlüssel in einen Mutex . Wenn Sie den Schlüssel zur Toilette mitnehmen (ein Schloss erwerben), können Sie ihn benutzen. Wenn es keinen Schlüssel gibt (das Schloss ist gesperrt), müssen Sie warten. Wenn der Schlüssel von der Person zurückgegeben wird (lassen Sie das Schloss los ), können Sie ihn jetzt erwerben.
Um MUTEX zu verstehen, müssen Sie zuerst wissen, was "Race Condition" ist, und dann werden nur Sie verstehen, warum MUTEX benötigt wird. Angenommen, Sie haben ein Multithreading-Programm und zwei Threads. Jetzt haben Sie einen Job in der Jobwarteschlange. Der erste Thread überprüft die Jobwarteschlange und beginnt nach dem Auffinden des Jobs mit der Ausführung. Der zweite Thread überprüft auch die Jobwarteschlange und stellt fest, dass sich ein Job in der Warteschlange befindet. Daher wird auch derselbe Jobzeiger zugewiesen. Was nun passiert, beide Threads führen denselben Job aus. Dies führt zu einem Segmentierungsfehler. Dies ist das Beispiel einer Rennbedingung.
Die Lösung für dieses Problem ist MUTEX. MUTEX ist eine Art Sperre, die jeweils einen Thread sperrt. Wenn ein anderer Thread es sperren möchte, wird der Thread einfach blockiert.
Das MUTEX-Thema in diesem PDF- Dateilink ist wirklich lesenswert.
Mutexe sind in Situationen nützlich, in denen Sie den exklusiven Zugriff auf eine Ressource über mehrere Prozesse hinweg erzwingen müssen, wobei eine reguläre Sperre nicht hilft, da sie nur über Threads hinweg funktioniert.
Mutex: Mutex steht für Mut ual Ex Folgerung. Dies bedeutet, dass jeweils ein Prozess / Thread in einen kritischen Abschnitt eintreten kann. Bei gleichzeitiger Programmierung, bei der mehrere Threads / Prozesse versuchen, die gemeinsam genutzte Ressource (eine Variable, ein gemeinsam genutzter Speicher usw.) zu aktualisieren, kann dies zu unerwarteten Ergebnissen führen. (Da das Ergebnis davon abhängt, welcher Thread / Prozess den ersten Zugriff erhält).
Um solch ein unerwartetes Ergebnis zu vermeiden, benötigen wir einen Synchronisationsmechanismus, der sicherstellt, dass jeweils nur ein Thread / Prozess Zugriff auf eine solche Ressource erhält.
Die pthread-Bibliothek bietet Unterstützung für 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
Dies ist die Struktur für den Mutex-Datentyp, dh pthread_mutex_t. Wenn der Mutex gesperrt ist, wird __lock auf 1 gesetzt. Wenn er entsperrt ist, wird __lock auf 0 gesetzt.
Dadurch wird sichergestellt, dass nicht zwei Prozesse / Threads gleichzeitig auf den kritischen Abschnitt zugreifen können.