pthreads Mutex vs Semaphor

73

Was ist der Unterschied zwischen Semaphoren und Mutex, die von der pthread-Bibliothek bereitgestellt werden?

cppdev
quelle
11
Semaphoren werden nicht von pthreads bereitgestellt und können auch in Programmen ohne Thread verwendet werden.
Ephemient
5
Jedes Synchronisationskonstrukt kann in Code ohne Thread verwendet werden: P
Hassan Syed
4
Nun, der Unterschied, den ich hervorheben wollte, ist, dass Semaphoren vor Pthreads verwendet wurden. Sie können ein sem_tim gemeinsam genutzten Speicher ablegen und damit Vorgänge zwischen Prozessen synchronisieren. Selbst wenn Sie nicht mehrere Threads erstellen, müssen Sie diese kompilieren und verknüpfen, -pthreadum sie verwenden zu können pthread_mutex_*. (Einige Plattformen erzwingen dies nicht, aber das ist der Standard.)
Ephemient
2
@ephemient, eigentlich man sem_initunter Linux, sagt: Link with -pthread.Ich denke also, dass Linux POSIX nicht genau folgt.
Alexis Wilke

Antworten:

78

Semaphoren haben einen synchronisierten Zähler und Mutexe sind nur binär (wahr / falsch).

Ein Semaphor wird häufig als endgültiger Mechanismus verwendet, um zu beantworten, wie viele Elemente einer Ressource verwendet werden. Beispielsweise kann ein Objekt, das n Arbeitsthreads darstellt, ein Semaphor verwenden, um zu zählen, wie viele Arbeitsthreads verfügbar sind.

Die Wahrheit ist, dass Sie ein Semaphor durch eine INT darstellen können, die durch einen Mutex synchronisiert wird.

Hassan Syed
quelle
157
Ein wesentlicher Unterschied (seit ich gesehen habe, dass Leute diesen Fehler gemacht haben): Ein Semaphor kann von jedem Thread in einer beliebigen Reihenfolge beschafft und geräumt werden (solange die Anzahl niemals negativ ist), aber ein Mutex kann nur vom Thread entsperrt werden das hat es verschlossen. Der Versuch, einen Mutex zu entsperren, der von einem anderen Thread gesperrt wurde, ist ein undefiniertes Verhalten.
Ephemient
5
@ Ephemient, das hätte eine großartige Antwort gegeben, sehr aufschlussreich
Matt Joiner
9
@ephemient: Aus dem von Ihnen angegebenen Grund ist die letzte Aussage in der Antwort falsch: Sie können kein Semaphor durch eine INT darstellen, die durch einen Mutex synchronisiert wird, da Sie, wenn der Mutex gehalten wird, den Int nicht von einem anderen inkrementieren / dekrementieren können Thread, und Sie müssen warten, bis der Sperr-Thread den Mutex freigibt. Der Hauptunterschied besteht darin, dass der Mutex im Besitz ist, während das Semaphor nicht im Besitz ist. Und dieses Eigentum wird durch die auferlegte Synchronisation an das INT übertragen. Sie erhalten also ein hybrides Semaphor, das sich im Besitz befindet, irgendwo zwischen dem nicht besessenen Semaphor und dem eigenen Mutex.
user1284631
18
Ich denke, diese Antwort übersieht immer noch eine SEHR entscheidende Unterscheidung zwischen einem Semaphor und einem Mutex; das ist die Verwendung. Semaphoren sind Signalmechanismen in ihrem Herzen; Die Tatsache, dass sie von jedem Thread inkrementiert und dekrementiert werden können, ist nur eine Folge davon. Semaphore werden verwendet, um anderen Kontrollflüssen etwas zu signalisieren, das mit der Synchronisation zusammenhängt (wie ein vollständig / leerer Puffer). Ein Mutex hingegen wird immer verwendet, um den Mehrfachzugriff auf ein freigegebenes Objekt zu schützen. Das ist ein großer Unterschied und die Leute scheinen es irgendwie immer zu vermissen, oder ich verstehe nie, was sie sagen wollen. : P
Fingolfin
18

Ich werde über Mutex vs Binary-Semaphore sprechen. Sie verwenden offensichtlich Mutex, um zu verhindern, dass ein anderer Thread gleichzeitig auf Daten in einem Thread zugreift.

(Angenommen, Sie haben gerade lock () aufgerufen und greifen gerade auf Daten zu. Dies bedeutet, dass Sie nicht erwarten, dass ein anderer Thread (oder eine andere Instanz desselben Thread-Codes) auf dieselben Daten zugreift, die von gesperrt sind Gleicher Mutex. Wenn also derselbe Thread-Code, der auf einer anderen Thread-Instanz ausgeführt wird, auf die Sperre trifft, sollte lock () den Kontrollfluss blockieren.)

Dies gilt für einen Thread, der einen anderen Thread-Code verwendet, der ebenfalls auf dieselben Daten zugreift und der auch von demselben Mutex gesperrt wird.

In diesem Fall sind Sie noch dabei, auf die Daten zuzugreifen, und es kann beispielsweise weitere 15 Sekunden dauern, bis die Mutex-Entsperrung erreicht ist (sodass der andere Thread, der in der Mutex-Sperre blockiert wird, entsperrt wird und die Steuerung dies zulässt Zugriff auf die Daten).

Erlauben Sie jemals einem anderen Thread, denselben Mutex zu entsperren, und lassen Sie wiederum den Thread, der bereits in der Mutex-Sperre wartet (blockiert), die Blockierung aufzuheben und auf die Daten zuzugreifen? (Ich hoffe, Sie haben verstanden, was ich hier sage.)

Gemäß der vereinbarten universellen Definition

  • mit "mutex" kann das nicht passieren. Kein anderer Thread kann die Sperre in Ihrem Thread aufheben
  • Mit „Binärsemaphor“ kann dies passieren. Jeder andere Thread kann die Sperre in Ihrem Thread aufheben

Wenn Sie also ganz besonders darauf bedacht sind, Binärsemaphor anstelle von Mutex zu verwenden, sollten Sie beim „Scoping“ der Sperren und Entsperrungen sehr vorsichtig sein. Ich meine, dass jeder Kontrollfluss, der jede Sperre trifft, einen Entsperraufruf und auch treffen sollte Es sollte keine "erste Entsperrung" geben, sondern immer "erste Sperre".

Paxi
quelle
Ich mag den Scoping- Teil. Es bezieht sich auf den Implementierungsteil, der sich in binärem Semaphor und Mutex unterscheidet.
Shuva
7

Mutex wird verwendet, um Race-Bedingungen zwischen mehreren Threads zu vermeiden.

Während Semaphor als Synchronisationselement verwendet wird, das über mehrere Prozesse hinweg verwendet wird.

Mutex kann nicht durch binäres Semaphor ersetzt werden, da ein Prozess auf das Semaphor wartet, während ein anderer Prozess das Semaphor freigibt. Im Fall von Mutex werden sowohl die Erfassung als auch die Freigabe von demselben behandelt.

C Lernender
quelle
1
(-1) Falsche Verallgemeinerung: Zum einen können Mutexe prozessübergreifend gemeinsam genutzt werden - zum Beispiel: msdn.microsoft.com/en-us/library/ms682411(VS.85).aspx . Wenn Ihr System keine Mutex-Namen hat, ordnen Sie einfach einen gemeinsam genutzten Speicher zu und erstellen Sie Ihren eigenen.
Hassan Syed
1
Es ist nicht fair, es als "nicht nützlich" zu kennzeichnen. Ich habe ziemlich viel an M $ gearbeitet. Es ist einfach, jemandem zu sagen, dass er Shared Memory verwenden soll. Auf M $ werden alle Kernelobjekte benannt und gemeinsam genutzt. Mutex ist ein Kernelobjekt. Ein Pthread-Mutex ist eine CRITICAL_SECTION in M ​​$. Es gibt keine Möglichkeit, CRITICAL_SECTION zwischen Prozessen zu teilen!
Hackworks
@hackworks - pthread_mutex kann mit dem Flag "_POSIX_THREAD_PROCESS_SHARED" initialisiert werden, das es ermöglicht, in einer Interprozessumgebung zu arbeiten: linux.die.net/man/3/pthread_mutexattr_init
killdaclick
6

Das Toilettenbeispiel

Mutex:

Ist ein Schlüssel zu einer Toilette. Eine Person kann den Schlüssel haben - die Toilette besetzen - zu der Zeit. Wenn Sie fertig sind, gibt die Person den Schlüssel an die nächste Person in der Warteschlange weiter (gibt ihn frei).

"Mutexe werden normalerweise verwendet, um den Zugriff auf einen Abschnitt des wiedereintretenden Codes zu serialisieren, der nicht gleichzeitig von mehr als einem Thread ausgeführt werden kann. Ein Mutex-Objekt lässt nur einen Thread in einen kontrollierten Abschnitt zu und zwingt andere Threads, die versuchen, Zugriff auf diesen Abschnitt zu erhalten warten, bis der erste Thread diesen Abschnitt verlassen hat. "

(Ein Mutex ist wirklich ein Semaphor mit dem Wert 1.)

Semaphor:

Ist die Anzahl der freien identischen Toilettenschlüssel. Nehmen wir zum Beispiel an, wir haben vier Toiletten mit identischen Schlössern und Schlüsseln. Die Anzahl der Semaphore - die Anzahl der Schlüssel - wird zu Beginn auf 4 gesetzt (alle vier Toiletten sind frei), und der Zählwert wird verringert, wenn Personen hereinkommen. Wenn alle Toiletten voll sind, d. H. Es sind keine freien Schlüssel mehr vorhanden. Die Anzahl der Semaphore beträgt 0. Wenn nun Gl. Eine Person verlässt die Toilette, das Semaphor wird auf 1 (ein freier Schlüssel) erhöht und der nächsten Person in der Warteschlange übergeben.

"Ein Semaphor beschränkt die Anzahl der gleichzeitigen Benutzer einer gemeinsam genutzten Ressource auf eine maximale Anzahl. Threads können den Zugriff auf die Ressource anfordern (Dekrementieren des Semaphors) und signalisieren, dass sie die Ressource nicht mehr verwenden (Inkrementieren des Semaphors)."

Quelle

Ankur
quelle
4

Der Unterschied zwischen semaphoreund mutexist der Unterschied zwischen Mechanismus und Muster . Der Unterschied liegt in ihrem Zweck ( Absicht ) und ihrer Funktionsweise ( Verhalten ).

Die mutex, barrier, pipelinesind parallel Programmiermuster . Mutexwird verwendet ( beabsichtigt ), um a zu schützen critical sectionund sicherzustellen mutual exclusion. BarrierLässt die Agenten (Thread / Prozess) weiter aufeinander warten.

Eines der Merkmale ( Verhalten ) des mutexMusters ist, dass nur zulässige Agenten (Prozesse oder Threads) einen kritischen Abschnitt betreten können und nur diese Agenten freiwillig aus diesem herauskommen können.

Es gibt Fälle, in denen jeweils ein mutexAgent zugelassen ist. Es gibt Fälle, in denen mehrere Agenten (mehrere Leser) zugelassen und einige andere Agenten (Schreiber) nicht zugelassen werden.

Dies semaphoreist ein Mechanismus , der verwendet werden kann ( beabsichtigt ), um verschiedene Muster zu implementieren. Es ist ( Verhalten ) im Allgemeinen eine Flagge (möglicherweise durch gegenseitigen Ausschluss geschützt). (Eine interessante Tatsache ist, dass sogar mutexMuster verwendet werden können, um Semaphor zu implementieren).

In der Populärkultur semaphoreswerden Mechanismen von Kerneln und mutexesvon User-Space-Bibliotheken bereitgestellt.

Beachten Sie, dass es falsche Vorstellungen über semaphoresund gibt mutexes. Es heißt, dass semaphoresfür verwendet werden synchronization. Und mutexeshat ownership. Dies ist auf beliebte OS-Bücher zurückzuführen. Aber die Wahrheit ist, dass alle Mutexe, Semaphoren und Barrieren für die Synchronisation verwendet werden . Die Absicht von Mutex ist ownershipaber nicht mutual exclusion. Dieses Missverständnis führte zu einer populären Interviewfrage, in der nach dem Unterschied zwischen mutexesund gefragt wurde binary-semaphores.

Zusammenfassung,

Absicht
  • Mutex, gegenseitiger Ausschluss
  • Semaphor, implementieren Sie parallele Entwurfsmuster
Verhalten
  • Mutex, nur der / die zugelassene (n) Agent (en) betritt (n) einen kritischen Bereich und nur dieser (sie) kann (n) verlassen
  • Semaphor, geben Sie ein, wenn die Flagge go sagt, andernfalls warten Sie, bis jemand die Flagge ändert

In der Entwurfsperspektive mutexist es eher so, als ob state-patternder vom Status ausgewählte Algorithmus den Status ändern kann. Dies binary-semaphoreist eher so, als ob strategy-patternder externe Algorithmus den Status und schließlich den Algorithmus / die Strategie ändern kann, die bzw. der zum Ausführen ausgewählt wurde.

Shuva
quelle
3

In diesen beiden Artikeln werden wichtige Details zu Mutex und Semaphoren erläutert. Auch diese Stapelüberlaufantwort gibt eine ähnliche Antwort.

Tsenapathie
quelle
1

Semaphor wird eher als Flag verwendet, für das Sie RTOS / OS wirklich nicht mitbringen müssen. Semaphor kann versehentlich oder absichtlich durch andere Threads geändert werden (z. B. aufgrund einer schlechten Codierung). Wenn Sie einen Thread verwenden, der Mutex verwendet, besitzt er die Ressourcen. Kein anderer Thread kann jemals darauf zugreifen, bevor die Ressource frei wird.

Ajinkya
quelle
0

Mutex ist wie ein Semaphor mit S = 1.

Sie können die Anzahl der gleichzeitigen Zugriffe mit Semaphor steuern, aber mit Mutex kann jeweils nur ein Prozess darauf zugreifen.

Siehe die Implementierung dieser beiden unten: (Alle Funktionen sind atomar)

Semaphor:

wait(S) {
      while (S <= 0 )
         ; // busy wait
      S--;
}

signal(S) {
      S++;
}

Mutex:

acquire() {
      while (!available)
            ; // busy wait
      available = false;
}

release() {
      available = true;
}
Ava
quelle