C++: Speichermodell

Consume-Release-Semantik

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
Die Consume-Release-Semantik ist nichts anderes als die Acquire-Release-Semantik ohne deren Ordnungsbedingungen.
05:09

Transkript

In dieser Lektion möchte ich Ihnen die Consume-Release-Semantik vorstellen. Die Consume-Release-Semantik ist ein Spezialfall der Acquire-Release-Semantik. Sie können sie sich einfach vorstellen als die Acquire-Release-Semantik ohne deren Ordnungsbedingungen. Die Consume-Release-Semantik ist legendär. Die Frage ist warum? Sie ist aus mehreren Gründen legendär. Zum einen, weil sie extrem verständnisresistent ist, darüber hinaus, weil jeder Compiler die Consume-Release-Semantik durch die Acquire-Release-Semantik umsetzt, und weil’s bis jetzt keinen Compiler gibt, der sie implementiert. Der GCC bot zeitweise die Consume-Release-Semantik an. Die GCC-Entwickler entdeckten aber dann einen ziemlich großen Bug in der Implementierung und haben’s wieder disabled. Jetzt fragen Sie sich vielleicht, wie kann’s sein, dass im Compiler C++11 standardkonform ist, obwohl die Consume-Release-Semantik nicht anbietet. Das ist ganz einfach, statt "memory_order_consume", verwenden die Compiler intern jetzt immer "memory_order_aquire". Das ist ein bisschen strenger, aber die Consume-Semantik ist sozusagen vorhanden, halt ein bisschen strenger. Um was geht’s bei der Consume-Release-Semantik? Es geht um Datenabhängigkeiten. Datenabhängigkeiten sind Abhängigkeiten, wenn ein Laden eines Datums von einem Schreiben des gleichen Datums, kurz davor, abhängt. Das ist eine Datenabhängigkeit. Und die gibt’s in zwei Geschmacksrichtungen: Die gibt’s mal in einem Thread, nennt sich dann "carries-a-dependency-to" oder zwischen Threads, nennt sich dann "dependency-ordered-before". Und das zeige ich jetzt an einem Beispiel. Ich fange mit der Acquire-Release-Semantik an, dann 'entere' ich ein kleines Flag und dann haben wir die Consume-Release-Semantik. Hier habe ich ihre Release-Operation, die Store-Operation mit einem Release-Tag annotiert, auf der atomaren Variable Pointer(ptr), und entsprechend hier eine Acquire-Operation auf Pointer(ptr) und dann habe ich die Garantie, dass die Release-Operation mit dieser Acquire-Operation sich synchronisiert und Ordnungsbedingung etabliert. Das ist die klassische Acquire-Release-Semantik. Die Ordnungsbedingungen sind die, dass alles, was hier davor stattfindet, also "string* p = new string", "data = 2011" und "atoData.store", das dies alles hier danach zur Verfügung steht. Und jetzt mache ich nur eine kleine Modifikation. Anstelle von "memory_order_acquire" schreibe ich hier "memory_order_consume". Jetzt argumentiere ich mit der Consume-Acquire-Semantic. Das bedeutet, dieses Store findet auf der gleichen Variable "Pointer" statt. Dies etabliert eine Datenabhängigkeit zu diesem "load", die gültig wird, weil ich das was ich hier lade und hier im "p2" speichere, eine Abhängigkeit zu dem "p2" aufbaut. Also was ich hier schreibe, lese ich hier. Und damit habe ich die Garantie, dass das Pointer "store" hier unten zur Verfügung steht. Und jetzt kommt der feine Unterschied. Mir fehlen aber hier die Ordnungsbedingungen. Das heißt, dass alles, was hier davor stattfindet, nicht automatisch hier hinten zur Verfügung steht, also nach dem "load". Weil diese Ordnungsbedingung gilt ja nicht bei der Consume-Acquire-Semantik. Um es ganz hart zu sagen, dieses Programm hier ist undefiniert. Warum? Ich schreibe hier auf "data". Data ist nicht atomar und ich lese hier "data". Jetzt habe ich nicht die Garantie, dass das hier, vor dem hier stattfindet. Anders ausgedrückt: Das Schreiben kann mit dem Lesen hier zeitgleich passieren. Das ist ein klassisches "Data Race" oder kritischer Wettlauf und damit ist das Programm undefiniert. Ich habe auch nicht die Garantie, dass das "atoData.store" hier, vor dem "atoData.load" stattfindet. Das heißt, es ist nicht garantiert, dass ich die 14, hier unten, lese. Jetzt zeige ich’s Ihnen nochmal aus einer anderen Perspektive, diesmal mit den Pfeilen, die die Abhängigkeiten verdeutlichen. Dieses "store" auf dem Pointer ist eine "dependency-ordered-before"-Beziehung mit diesem "load". Sie findet auf dem gleichen atomaren Data-Point statt, weil das, was ich hier lade im"p2", eine "carries-a-dependency-to"-Relation zu dem "p2" hier aufbaut, weil ich’s ja hier lese. Und jetzt argumentiere ich wieder mit der Transivität. Das "ptr.store" ist "dependency-ordered-before", damit ist es "happens before". Das hier ist "carries-a-dependency-to", also ist es auch "happens before". Dann "happens-before" ist transitiv und somit habe ich die Garantie, dass dieses "ptr.store" hier, vor dem "p2" hier unten ausgeführt wird. In dieser Lektion habe ich Ihnen die sogenannte Consume-Acquire-Semantik vorgestellt. Die Consume-Acquire-Semantik ist legendär. Legendär aus zwei Gründen im Wesentlichen. Erstens, weil sie sehr verständnisresistent ist und zweitens, weil sie kein Compiler bisher umgesetzt hat.

C++: Speichermodell

Verstehen und nutzen Sie die Konzepte und die zugrundeliegenden TEchnolgien des Speichermodells in C++.

1 Std. 29 min (29 Videos)
Derzeit sind keine Feedbacks vorhanden...
Software:
Exklusiv für Abo-Kunden
Erscheinungsdatum:24.11.2016

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!