Ich habe einen Punkt in meinem Projekt erreicht, der die Kommunikation zwischen Threads auf Ressourcen erfordert, auf die sehr gut geschrieben werden kann, so dass Synchronisation ein Muss ist. Allerdings verstehe ich Synchronisation nicht wirklich etwas anderes als die grundlegende Ebene.
Betrachten Sie das letzte Beispiel in diesem Link: Ссылка
%Vor%Das Beispiel zeigt, wie drei Threads, zwei Writer und ein Reader, auf eine gemeinsame Ressource (Liste) zugreifen.
Es werden zwei globale Funktionen verwendet: eine, die von den beiden Writer-Threads verwendet wird, und eine, die vom Leser-Thread verwendet wird. Beide Funktionen verwenden einen lock_guard, um dieselbe Ressource, die Liste, zu sperren.
Nun, hier ist, was ich nicht um den Kopf wickeln kann: Der Leser verwendet eine Sperre in einem anderen Bereich als die beiden Writer-Threads und sperrt trotzdem die gleiche Ressource. Wie kann das funktionieren? Mein begrenztes Verständnis von Mutexen eignet sich gut für die Writer-Funktion, da gibt es zwei Threads, die die exakt gleiche Funktion verwenden. Ich kann das verstehen, eine Überprüfung wird richtig gemacht, wenn Sie den geschützten Bereich betreten wollen, und wenn jemand anderes schon drinnen ist, warten Sie.
Aber wenn der Umfang anders ist? Dies würde anzeigen, dass es eine Art von Mechanismus gibt, der leistungsfähiger ist als der Prozess selbst, eine Art Laufzeitumgebung, die die Ausführung des "späten" Threads blockiert. Aber ich dachte, es gäbe keine solchen Dinge in C ++. So bin ich ratlos.
Was genau geht hier unter der Haube vor?
myMutex
ist global, was zum Schutz von myList
verwendet wird. guard(myMutex)
greift einfach in das Schloss und der Ausgang aus dem Block verursacht seine Zerstörung, wodurch das Schloss gelöst wird. guard
ist nur eine bequeme Möglichkeit, das Schloss zu aktivieren und zu deaktivieren.
Damit wird mutex
keine Daten schützen. Es bietet nur eine Möglichkeit zum Schutz von Daten. Es ist das Entwurfsmuster, das Daten schützt. Wenn ich also meine eigene Funktion schreibe, um die Liste wie folgt zu ändern, kann mutex
sie nicht schützen.
Die Sperre funktioniert nur, wenn alle Code-Teile, die auf die Daten zugreifen müssen, die Sperre aktivieren, bevor sie auf sie zugreifen und sie wieder loslassen, nachdem sie ausgeführt wurden. Dieses Design-Muster des Ein- und Ausschaltens der Sperre vor und nach jedem Zugriff schützt die Daten ( myList
in Ihrem Fall)
Nun würden Sie sich fragen, warum mutex
überhaupt verwendet wird und warum nicht, sagen wir, bool
. Und ja, Sie können, aber Sie müssen sicherstellen, dass die Variable bool
bestimmte Eigenschaften aufweist, einschließlich, aber nicht beschränkt auf die folgende Liste.
Es gibt verschiedene synchronization
-Mechanismen, die "besseres Sperren" (über Prozesse im Vergleich zu Threads, mehrere Prozessoren im Vergleich zu Einzelprozessoren usw.) zu Kosten einer "langsameren Leistung" bieten. Daher sollten Sie immer einen Sperrmechanismus wählen, der ist gerade genug für deine Situation.
Sehen wir uns die entsprechende Zeile an:
%Vor% Beachten Sie, dass lock_guard
auf den globalen Mutex myMutex
verweist. Das heißt, der gleiche Mutex für alle drei Threads. Was lock_guard
macht, ist im Wesentlichen das:
myMutex
gesperrt und ein Verweis darauf beibehalten. myMutex
freigegeben. Der Mutex ist immer derselbe, er hat nichts mit dem Oszilloskop zu tun. Der Punkt lock_guard
dient lediglich dazu, das Sperren und Entsperren des Mutex für Sie einfacher zu machen. Wenn Sie beispielsweise lock
/ unlock
manuell setzen, aber Ihre Funktion irgendwo in der Mitte eine Ausnahme auslöst, wird sie nie die unlock
-Anweisung erreichen. Wenn Sie also den manuellen Weg Sie machen, müssen Sie sicherstellen, dass der Mutex immer freigeschaltet ist. Auf der anderen Seite wird das Objekt lock_guard
automatisch zerstört, wenn die Funktion beendet wird - unabhängig davon, wie sie beendet wird.
Genau das macht eine Sperre. Wenn ein Thread die Sperre übernimmt, unabhängig davon, wo im Code dies geschieht, muss er warten, bis ein anderer Thread die Sperre hält. Wenn ein Thread eine Sperre freigibt, unabhängig davon, wo im Code dies geschieht, kann ein anderer Thread diese Sperre erlangen.
Sperren schützen Daten, nicht Code. Sie tun dies, indem sie sicherstellen, dass der gesamte Code, der auf die geschützten Daten zugreift, während sie die Sperre hält, andere Threads von jedem Code ausschließt, die möglicherweise auf dieselben Daten zugreifen.
Tags und Links c++ multithreading thread-safety