20 - 4.2 Thread-Koordinierung: Nichtblockierende Synchronisation [ID:26430]
50 von 134 angezeigt

Mit Mutexen haben wir nun ein Mittel zur blockierenden Synchronisation kennengelernt.

Ähnlich wie es mit den Simaphoren ist.

Im Gegensatz dazu wollen wir uns im folgenden Mal die nicht blockierende Synchronisation

anschauen.

Der wesentliche Unterschied im Einsatz von nicht blockierender und blockierender Synchronisation

ist, dass wir im blockierenden Fall ein pessimistisches Anwendungsszenario haben.

Das bedeutet, wir gehen davon aus, dass auf kritische Abschnitte, die wir schützen müssen,

häufig gleichzeitig zugegriffen wird.

Dementsprechend müssen wir gegenseitigen Ausschluss schaffen, damit dies eben nicht

vorkommt.

Im optimistischen Fall hingegen gehen wir davon aus, dass der Zugriff auf ein kritisches

Datum relativ selten geschieht.

Dementsprechend müssen wir nicht präventiv den kritischen Abschnitt schützen, sondern

können einfach beginnen, die Daten zu lesen und zu bearbeiten.

Und erst wenn wir ein Ergebnis haben, das wir zurückschreiben wollen, prüfen wir, ob

in der Zwischenzeit ein anderer Thread bereits die ursprünglichen Daten verändert hat.

Falls dies der Fall ist, verwerfen wir unser Ergebnis und wiederholen den Prozess.

Hier sind wir optimistisch und gehen davon aus, dass dies selten geschieht.

Um nicht blockierende Synchronisation zu implementieren, brauchen wir oft Unterstützung von der Hardware,

zum Beispiel in Form von bestimmten Instruktionen wie der CAS-Operation, dem Compare and Swap.

Mehr Details dazu gibt es in der Vorlesung.

Die Compare and Swap-Operation hat folgende Eigenschaften.

Sie erwartet drei Argumente.

Einmal eine Speicheradresse, auf die sie zugreifen soll und das zweite Argument ist der Wert,

von dem wir erwarten, dass es sich dahinter befindet.

Und das dritte Argument ist ein Wert, der an die Speicherstelle geschrieben werden soll.

Was nun also passiert bei der Ausführung von Compare and Swap ist, dass die Operation

in einem atomaren Schritt, das heißt gleichzeitig, prüft, ob an der gewählten Speicherstelle

genau der Wert steht, den wir erwarten und falls dies der Fall ist, wird dieser überschrieben

mit dem dritten Argument.

Außerdem können wir anhand des Rückgabewerts feststellen, ob ein Schreibzugriff nun stattgefunden

hat oder nicht.

Die Verwendung der CAS-Operation sieht nun typischerweise so aus.

Wir holen uns eine lokale Kopie einer kritischen Variable.

Anschließend können wir Berechnungen durchführen.

Und sobald wir fertig sind, können wir nun versuchen, das Ergebnis, das wir neu berechnet

haben, zurückzuschreiben.

Dafür prüfen wir einmal, ob der alte Wert, den wir uns kopiert haben, noch immer an der

entsprechenden Speicheradresse steht.

Damit können wir feststellen, ob in der Zwischenzeit ein anderer Thread darauf zugegriffen hat

oder nicht.

Falls kein anderer Thread darauf zugegriffen hat, können wir unser Ergebnis wegspeichern.

Das machen wir mit der CAS-Operation.

Nun müssen wir aber auf den Fall vorbereitet sein, dass eben in der Zwischenzeit doch ein

anderer Thread es geschafft hat, sein Wert abzuspeichern, so dass bei uns die CAS-Operation

den Rückgabewert falls hat.

In dem Fall müssen wir den gesamten Vorgang wiederholen, das bedeutet, wir holen uns

erneut eine lokale Kopie der kritischen Variable und berechnen unser Ergebnis neu.

Schließlich können wir wieder versuchen, das Ergebnis wegzuschreiben.

Und dies geht so lange, bis es uns einmal gelingt.

Teil einer Videoserie :

Zugänglich über

Offener Zugang

Dauer

00:08:04 Min

Aufnahmedatum

2020-12-14

Hochgeladen am

2020-12-14 09:30:10

Sprache

de-DE

Einbetten
Wordpress FAU Plugin
iFrame
Teilen