Wann sollten wir Mutex verwenden und wann sollten wir Semaphor verwenden?
Wann sollten wir Mutex verwenden und wann sollten wir Semaphor verwenden?
Antworten:
So erinnere ich mich, wann ich was verwenden soll -
Semaphor: Verwenden Sie ein Semaphor, wenn Sie (Thread) schlafen möchten, bis ein anderer Thread Sie auffordert, aufzuwachen. Das Semaphor 'down' tritt in einem Thread (Produzent) und das Semaphor 'up' (für dasselbe Semaphor) in einem anderen Thread (Consumer) auf. Beispiel: Bei Producer-Consumer-Problemen möchte der Produzent schlafen, bis mindestens ein Pufferschlitz leer ist - nur Der Consumer-Thread kann erkennen, wann ein Puffersteckplatz leer ist.
Mutex: Verwenden Sie einen Mutex, wenn Sie (Thread) Code ausführen möchten, der nicht gleichzeitig von einem anderen Thread ausgeführt werden soll. Mutex 'down' kommt in einem Thread vor und Mutex 'up' muss später im selben Thread vorkommen. Beispiel: Wenn Sie einen Knoten aus einer globalen verknüpften Liste löschen, möchten Sie nicht, dass ein anderer Thread beim Löschen des Knotens mit Zeigern herumfummelt. Wenn Sie einen Mutex erwerben und gerade einen Knoten löschen und ein anderer Thread versucht, denselben Mutex abzurufen, wird dieser in den Ruhezustand versetzt, bis Sie den Mutex freigeben.
Spinlock: Verwenden Sie einen Spinlock, wenn Sie wirklich einen Mutex verwenden möchten, Ihr Thread jedoch nicht schlafen darf. Beispiel: Ein Interrupt-Handler im OS-Kernel darf niemals schlafen. In diesem Fall friert das System ein / stürzt ab. Wenn Sie vom Interrupt-Handler einen Knoten in eine global freigegebene verknüpfte Liste einfügen müssen, erwerben Sie einen Spinlock - Knoten einfügen - Spinlock freigeben.
Ein Mutex ist ein Objekt zum gegenseitigen Ausschluss, ähnlich einem Semaphor, das jedoch jeweils nur ein Schließfach zulässt und dessen Eigentumsbeschränkungen möglicherweise strenger sind als ein Semaphor.
Es kann als äquivalent zu einem normalen Zählsemaphor (mit einer Zählung von eins) und der Anforderung angesehen werden, dass es nur von demselben Thread freigegeben werden kann, der es gesperrt hat (a) .
Ein Semaphor hingegen hat eine beliebige Anzahl und kann von so vielen Schließfächern gleichzeitig gesperrt werden. Und es kann nicht erforderlich sein, dass es von demselben Thread veröffentlicht wird, der es beansprucht hat (aber wenn nicht, müssen Sie sorgfältig verfolgen, wer derzeit dafür verantwortlich ist, ähnlich wie der zugewiesene Speicher).
Wenn Sie also mehrere Instanzen einer Ressource haben (z. B. drei Bandlaufwerke), können Sie ein Semaphor mit einer Anzahl von 3 verwenden. Beachten Sie, dass dies Ihnen nicht sagt, welches dieser Bandlaufwerke Sie haben, sondern nur, dass Sie haben eine bestimmte Anzahl.
Auch mit Semaphoren ist es möglich, dass ein einzelnes Schließfach mehrere Instanzen einer Ressource sperrt, z. B. für eine Band-zu-Band-Kopie. Wenn Sie über eine Ressource verfügen (z. B. einen Speicherort, den Sie nicht beschädigen möchten), ist ein Mutex besser geeignet.
Äquivalente Operationen sind:
Counting semaphore Mutual exclusion semaphore
-------------------------- --------------------------
Claim/decrease (P) Lock
Release/increase (V) Unlock
Nebenbei: Falls Sie sich jemals über die bizarren Buchstaben gewundert haben, mit denen Semaphoren beansprucht und veröffentlicht wurden, liegt dies daran, dass der Erfinder Niederländer war. Probeer te verlagen bedeutet zu versuchen, abzunehmen, während verhogen zu erhöhen bedeutet.
(a) ... oder es kann als etwas völlig anderes als ein Semaphor angesehen werden, das aufgrund seiner fast immer unterschiedlichen Verwendung sicherer sein kann.
Es ist sehr wichtig zu verstehen, dass ein Mutex kein Semaphor mit Zählung 1 ist!
Dies ist der Grund, warum es Dinge wie binäre Semaphoren gibt (die wirklich Semaphoren mit Zählung 1 sind).
Der Unterschied zwischen einem Mutex und einem Binärsemaphor ist das Prinzip des Eigentums:
Ein Mutex wird von einer Aufgabe erfasst und muss daher auch von derselben Aufgabe freigegeben werden. Dies ermöglicht es, mehrere Probleme mit binären Semaphoren zu beheben (versehentliche Freigabe, rekursiver Deadlock und Prioritätsinversion).
Vorsichtsmaßnahme: Ich schrieb "macht es möglich", ob und wie diese Probleme behoben werden, hängt von der Implementierung des Betriebssystems ab.
Da der Mutex von derselben Aufgabe freigegeben werden muss, ist er für die Synchronisierung von Aufgaben nicht sehr gut. In Kombination mit Bedingungsvariablen erhalten Sie jedoch sehr leistungsfähige Bausteine zum Erstellen aller Arten von IPC-Grundelementen.
Meine Empfehlung lautet also: Wenn Sie Mutexe und Bedingungsvariablen (wie bei POSIX-Pthreads) sauber implementiert haben, verwenden Sie diese.
Verwenden Sie Semaphore nur, wenn sie genau zu dem Problem passen, das Sie lösen möchten. Versuchen Sie nicht, andere Grundelemente zu erstellen (z. B. rw-Sperren aus Semaphoren, verwenden Sie Mutexe und Bedingungsvariablen für diese).
Es gibt viele Missverständnisse bei Mutexen und Semaphoren. Die beste Erklärung, die ich bisher gefunden habe, ist in diesem dreiteiligen Artikel:
Mutex vs. Semaphoren - Teil 1: Semaphoren
Mutex vs. Semaphoren - Teil 2: Der Mutex
Mutex vs. Semaphoren - Teil 3 (letzter Teil): Probleme des gegenseitigen Ausschlusses
Obwohl die Antwort von @opaxdiablo völlig korrekt ist, möchte ich darauf hinweisen, dass das Verwendungsszenario beider Dinge sehr unterschiedlich ist. Der Mutex wird verwendet, um Teile des Codes vor der gleichzeitigen Ausführung zu schützen. Semaphoren werden für einen Thread verwendet, um die Ausführung eines anderen Threads zu signalisieren.
/* Task 1 */
pthread_mutex_lock(mutex_thing);
// Safely use shared resource
pthread_mutex_unlock(mutex_thing);
/* Task 2 */
pthread_mutex_lock(mutex_thing);
// Safely use shared resource
pthread_mutex_unlock(mutex_thing); // unlock mutex
Das Semaphorszenario ist anders:
/* Task 1 - Producer */
sema_post(&sem); // Send the signal
/* Task 2 - Consumer */
sema_wait(&sem); // Wait for signal
Weitere Erläuterungen finden Sie unter http://www.netrino.com/node/202
sema_wait
:-) Meiner Meinung nach geht es sowohl um Ressourcen als auch um die Benachrichtigung, die an andere Threads weitergegeben wird, ist ein Nebeneffekt (sehr wichtig, leistungsmäßig) der Schutz.
You say that the usage pattern of semaphores is to notify threads
Ein Punkt zum Benachrichtigen von Threads. Sie können anrufen sem_post
aus einem Signal - Handler sicher ( pubs.opengroup.org/onlinepubs/009695399/functions/... ) , aber es ist nicht auf Anruf empfohlen pthread_mutex_lock
und pthread_mutex_unlock
von Signal - Handler ( manpages.ubuntu.com/manpages/lucid/man3/... )
Siehe "Das Toilettenbeispiel" - http://pheatt.emporia.edu/courses/2010/cs557f10/hand07/Mutex%20vs_%20Semaphore.htm :
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).
Offiziell: "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 erlaubt nur einen Thread in einen kontrollierten Abschnitt, wodurch andere Threads gezwungen werden, auf die zugegriffen werden soll diesen Abschnitt, um zu warten, bis der erste Thread diesen Abschnitt verlassen hat. " Ref: Symbian Developer Library
(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.
Offiziell: "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). "" Ref: Symbian Developer Library
Ich versuche nicht verrückt zu klingen, kann mir aber nicht helfen.
Ihre Frage sollte sein, was der Unterschied zwischen Mutex und Semaphoren ist. Genauer gesagt sollte die Frage lauten: Wie ist die Beziehung zwischen Mutex und Semaphoren?
(Ich hätte diese Frage hinzugefügt, bin mir aber hundertprozentig sicher, dass ein übereifriger Moderator sie als Duplikat schließen würde, ohne den Unterschied zwischen Unterschied und Beziehung zu verstehen.)
In der Objektterminologie können wir Folgendes beobachten:
Beobachtung.1 Semaphor enthält Mutex
Beobachtung.2 Mutex ist kein Semaphor und Semaphor ist kein Mutex.
Es gibt einige Semaphore, die so tun, als wären sie Mutex, sogenannte binäre Semaphoren, aber sie flippen NICHT Mutex aus.
Es gibt eine spezielle Zutat namens Signaling (posix verwendet condition_variable für diesen Namen), die erforderlich ist, um aus Mutex ein Semaphor zu machen. Betrachten Sie es als Benachrichtigungsquelle. Wenn zwei oder mehr Threads dieselbe Benachrichtigungsquelle abonniert haben, ist es möglich, diese Nachricht entweder an EINEN oder an ALLE zu senden, um sie zu aktivieren.
Mit Semaphoren können ein oder mehrere Zähler verknüpft sein, die durch Mutex geschützt sind. Das einfachste Szenario für Semaphore ist, dass es einen einzelnen Zähler gibt, der entweder 0 oder 1 sein kann.
Hier strömt Verwirrung wie Monsunregen herein.
Ein Semaphor mit einem Zähler, der 0 oder 1 sein kann, ist KEIN Mutex.
Mutex hat zwei Zustände (0,1) und einen Besitz (Aufgabe). Semaphor hat einen Mutex, einige Zähler und eine Bedingungsvariable.
Verwenden Sie jetzt Ihre Vorstellungskraft, und jede Kombination aus Verwendung des Zählers und dem Zeitpunkt des Signals kann eine Art Semaphor ergeben.
Einzelner Zähler mit dem Wert 0 oder 1 und Signalisierung, wenn der Wert auf 1 geht UND dann einen der auf das Signal wartenden Typen entsperrt == Binäres Semaphor
Einzelner Zähler mit dem Wert 0 bis N und Signalisierung, wenn der Wert kleiner als N ist, und Sperren / Warten, wenn der Wert N ist == Zählsemaphor
Einzelner Zähler mit dem Wert 0 bis N und Signalisierung, wenn der Wert auf N geht, und Sperren / Warten, wenn der Wert kleiner als N == Barrieresemaphor ist (nun, wenn sie ihn nicht aufrufen, sollten sie es tun.)
Nun zu Ihrer Frage, wann was zu verwenden ist. (ODER eher die korrekte Frage Version 3, wann Mutex und wann Binärsemaphor verwendet werden soll, da es keinen Vergleich mit Nicht-Binärsemaphor gibt.) Verwenden Sie Mutex, wenn 1. Sie ein benutzerdefiniertes Verhalten wünschen, das nicht von Binär bereitgestellt wird Semaphor, wie Spin-Lock oder Fast-Lock oder rekursive Sperren. Normalerweise können Sie Mutexe mit Attributen anpassen, aber das Anpassen von Semaphoren ist nichts anderes als das Schreiben eines neuen Semaphors. 2. Sie möchten ein leichtes oder schnelleres Grundelement
Verwenden Sie Semaphoren, wenn genau das, was Sie wollen, von ihnen bereitgestellt wird.
Wenn Sie nicht verstehen, was Ihre Implementierung von Binärsemaphor bietet, verwenden Sie meiner Meinung nach Mutex.
Und zum Schluss lesen Sie ein Buch, anstatt sich nur auf SO zu verlassen.
Ich denke, die Frage sollte der Unterschied zwischen Mutex und binärem Semaphor sein.
Mutex = Es handelt sich um einen Besitzersperrmechanismus. Nur der Thread, der die Sperre erwirbt, kann die Sperre aufheben.
binäres Semaphor = Es ist eher ein Signalmechanismus, jeder andere Thread mit höherer Priorität kann, wenn gewünscht, signalisieren und die Sperre übernehmen.
Mutex dient zum Schutz der gemeinsam genutzten Ressource.
Semaphor soll die Fäden versenden.
Mutex:
Stellen Sie sich vor, es gibt einige Tickets zu verkaufen. Wir können einen Fall simulieren, in dem viele Leute die Tickets gleichzeitig kaufen: Jede Person ist ein Thread, um Tickets zu kaufen. Natürlich müssen wir den Mutex verwenden, um die Tickets zu schützen, da es sich um die gemeinsam genutzte Ressource handelt.
Semaphor:
Stellen Sie sich vor, wir müssen eine Berechnung wie folgt durchführen:
c = a + b;
Außerdem benötigen wir eine Funktion geta()
zum Berechnen a
, eine Funktion getb()
zum Berechnen b
und eine Funktion getc()
zum Berechnen c = a + b
.
Natürlich können wir nicht tun , das c = a + b
es sei denn , geta()
und getb()
beendet worden sind .
Wenn die drei Funktionen drei Threads sind, müssen wir die drei Threads versenden.
int a, b, c;
void geta()
{
a = calculatea();
semaphore_increase();
}
void getb()
{
b = calculateb();
semaphore_increase();
}
void getc()
{
semaphore_decrease();
semaphore_decrease();
c = a + b;
}
t1 = thread_create(geta);
t2 = thread_create(getb);
t3 = thread_create(getc);
thread_join(t3);
Mit Hilfe des Semaphors kann der obige Code sicherstellen, dass er t3
seine Arbeit erst dann erledigt, wenn t1
undt2
hat ihre Arbeit getan.
Mit einem Wort, Semaphor soll Threads als logische Reihenfolge ausführen lassen, während Mutex die gemeinsam genutzte Ressource schützen soll.
Sie sind also NICHT dasselbe, auch wenn manche Leute immer sagen, dass Mutex ein spezielles Semaphor mit dem Anfangswert 1 ist. Sie können dies auch so sagen, aber bitte beachten Sie, dass sie in verschiedenen Fällen verwendet werden. Ersetzen Sie nicht eins durch das andere, auch wenn Sie das können.
x = getx(); y = gety(); z = x + y;
Aus irgendeinem Grund verwenden wir drei Themen , die drei Dinge zu tun, jetzt die Reihenfolge der Themen ist sehr wichtig , weil wir nicht tun können , x + y
es sei denn , getx
und gety
fertig. Mit einem Wort, Semaphor wird verwendet, wenn wir uns um die Reihenfolge der Ausführung von Multithreading kümmern.
x
und abgeschlossen y
sind, dann berechnen z = x + y
. Ich weiß, Java hat CyclicBarrier
. Ich bin mir auch nicht sicher, ob ich sagen kann, dass mapreduce
Semaphor auch verwendet wird, weil ich es nicht kann, reduce
bis alle map
s abgeschlossen sind.
Alle oben genannten Antworten sind von guter Qualität, aber dies ist nur zum Auswendiglernen. Der Name Mutex leitet sich von " Gegenseitig ausschließend" ab. Daher sind Sie motiviert, sich eine Mutex-Sperre als gegenseitigen Ausschluss zwischen zwei wie in jeweils nur einem vorzustellen, und wenn ich besaß es kann man erst haben, nachdem ich es freigegeben habe. Andererseits existiert ein solcher Fall für Semaphore nicht wie ein Verkehrssignal (was das Wort Semaphore auch bedeutet).
Wie bereits erwähnt, ist ein Semaphor mit einer Zählung von eins dasselbe wie ein 'binäres' Semaphor, das dasselbe wie ein Mutex ist.
Die wichtigsten Dinge, die ich gesehen habe, sind Semaphoren mit einer größeren Anzahl als einer, für die verwendet wird, Produzenten / Konsumenten-Situationen, in denen Sie eine Warteschlange mit einer bestimmten festen Größe haben.
Sie haben dann zwei Semaphoren. Das erste Semaphor wird anfänglich auf die Anzahl der Elemente in der Warteschlange gesetzt, und das zweite Semaphor wird auf 0 gesetzt. Der Produzent führt eine P-Operation für das erste Semaphor aus und fügt es der Warteschlange hinzu. und führt eine V-Operation auf der zweiten aus. Der Verbraucher führt eine P-Operation für das zweite Semaphor aus, entfernt sie aus der Warteschlange und führt dann eine V-Operation für das erste aus.
Auf diese Weise wird der Produzent blockiert, wenn er die Warteschlange füllt, und der Verbraucher wird blockiert, wenn die Warteschlange leer ist.
Ein Mutex ist ein Sonderfall eines Semaphors. Ein Semaphor ermöglicht es mehreren Threads, in den kritischen Abschnitt zu gelangen. Beim Erstellen eines Semaphors definieren Sie, wie Threads im kritischen Abschnitt zulässig sein dürfen. Natürlich muss Ihr Code mehrere Zugriffe auf diesen kritischen Abschnitt verarbeiten können.
Binäres Semaphor und Mutex sind unterschiedlich. Aus Sicht des Betriebssystems werden ein binäres Semaphor und ein Zählsemaphor auf die gleiche Weise implementiert, und ein binäres Semaphor kann den Wert 0 oder 1 haben.
Mutex -> Kann nur für einen einzigen Zweck des gegenseitigen Ausschlusses für einen kritischen Codeabschnitt verwendet werden.
Semaphor -> Kann zur Lösung verschiedener Probleme verwendet werden. Ein binäres Semaphor kann zur Signalisierung verwendet werden und auch das Problem des gegenseitigen Ausschlusses lösen. Wenn es auf 0 initialisiert wird , löst es das Signalisierungsproblem und wenn es auf 1 initialisiert wird , löst es das Problem des gegenseitigen Ausschlusses .
Wenn die Anzahl der Ressourcen größer ist und synchronisiert werden muss, können wir das Zählsemaphor verwenden.
In meinem Blog habe ich diese Themen ausführlich besprochen.
https://designpatterns-oo-cplusplus.blogspot.com/2015/07/synchronization-primitives-mutex-and.html