Was ist ein Mutex?

650

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?

bmurphy1976
quelle
2
Hier ist ein guter Artikel über den Unterschied: barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore
Adam Davis
Ein Tutorial über Mutex kann helfen, die Dinge zu klären: stackoverflow.com/questions/4989451/mutex-example-tutorial
Nav
1
Ein Mutex ist wie ein Badezimmerschlüssel an einer Tankstelle, der sicherstellt, dass jeweils nur eine Person das Badezimmer benutzt UND dass niemand anderes die Toilette benutzt, bis der aktuelle Insasse fertig ist und der Schlüssel zurückgegeben wird.
Jonschlinkert

Antworten:

2146

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.

Xetius
quelle
9
Gute Antwort. Könnte man argumentieren, dass der Mutex tatsächlich die Regeln sind, die verhindern, dass das Huhn weitergegeben wird? und das Huhn ist das, was Sie abschließen?
SirYakalot
3
@ SirYakalot, du meinst, das Huhn ist die Ressource und der Moderator ist der Mutex?
Owen
155
Das Huhn ist der Mutex . Die Leute, die das Huhn hupen, sind konkurrierende Fäden . Der Moderator ist das Betriebssystem . Wenn Leute das Huhn anfordern, machen sie eine Sperranfrage. Wenn Sie mutex.lock () aufrufen, bleibt Ihr Thread in lock () stehen und sendet eine Sperranforderung an das Betriebssystem. Wenn das Betriebssystem erkennt, dass der Mutex von einem Thread freigegeben wurde, gibt es ihn lediglich an Sie weiter und lock () kehrt zurück - der Mutex gehört jetzt Ihnen und nur Ihnen. Niemand sonst kann es stehlen, weil der Aufruf von lock () ihn blockiert. Es gibt auch try_lock (), das true blockiert und zurückgibt, wenn Mutex Ihnen gehört, und sofort false, wenn Mutex verwendet wird.
21етър Петров
4
Du bist ein Genie. Können Sie auch Monitore aus Gummi verwenden, um Monitore zu erklären?
Riccardo
98
Manchmal ist der Ursprung einiger Programmierkonzepte unklar. Ein Neuling könnte sich fragen, warum alle über Regex sprechen. Es ist nicht offensichtlich, dass Regex für [reguläre] Expression steht. In ähnlicher Weise steht Mutex für [gegenseitigen] Ausschluss. Dies könnte die Bedeutung des Begriffs leichter verdaulich machen. @TheSmurf hat in ihrer Antwort darauf verlinkt, aber es könnte gut sein, es hier für historische Zwecke hinzuzufügen.
Dodzi Dzakuma
137

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

Craig
quelle
10
Ein Mutex hat nichts mit einem Codeabschnitt an sich zu tun, er schützt eine Ressource. Diese Ressource kann ein Codesegment sein, wenn der Mutex immer nur um diesen Code herum verwendet wird. Sobald Sie den Mutex jedoch an mehreren Stellen in Ihrem Code verwenden, schlägt Ihre Erklärung fehl. In der Regel kann es auch zum Schutz einer Datenstruktur verwendet werden, auf die von vielen Stellen im Code aus zugegriffen werden kann.
Paxdiablo
72

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.

Der Schlumpf
quelle
64

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).

Mats Fredriksson
quelle
26

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.

Anthony Mastrean
quelle
1
Dies ist eine implementierungsabhängige Antwort. In CS unterscheidet sich ein Monitor auch von Mutex. Monitore haben einen Synchronisationsmechanismus, aber Mutex sperrt das Ding nur, bis es nicht mehr benötigt wird. IDK über Implementierungsdetails oder C #
-Semantik
23

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

MSDN-Referenz-Mutex

habib
quelle
1
ein sehr gutes Beispiel
Siwei Shen 23
21

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.

Chen A.
quelle
Das c # -Beispiel unterstützt jedoch nicht die Behauptung Ihrer Warteschlange "Übergeben Sie den Schlüssel an die nächste Person in der Warteschlange". Das Beispiel zeigt einen Stapel oder Zufall. 1, 2 und 3 fordern alle Zugriff in dieser Reihenfolge an. Einer ist zuerst in den geschützten Bereich erlaubt, und dann sind drei erlaubt. Eine Warteschlange hätte es der Sekunde gegeben.
Donvnielsen
Ich bezog mich nicht auf eine konkrete Implementierung oder eine konkrete Programmiersprache. Mein Beispiel bezieht sich auf die Abstraktion von Mutex auf hoher Ebene als Prinzip.
Chen A.
18

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.

user3751012
quelle
Mit "MUTEX-Thema" meinten Sie den Abschnitt über Semaphoren, weil seine Beispiele binäre Semaphoren sind, oder?
Carl G
2
Nun,
Wie heißt das Buch des Kapitels, das Sie geteilt haben? Bitte
Omar Faroque Anik
@OmarFaroqueAnik Das Buch, auf das verwiesen wird, ist Advanced Linux Programming von CodeSourcery LLC, veröffentlicht von New Riders Publishing und kann über die Homepage der verlinkten Domain aufgerufen werden.
RMart
11

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.

18 Stunden
quelle
Ist das wirklich wahr? Erstellen einzelne Prozesse keine eigene Mutex-Kopie?
Leon
0

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.

Sandeep_black
quelle