Ich suche nach einem Äquivalent von LWARX und STWCX (wie es auf den PowerPC-Prozessoren zu finden ist) oder nach einer Möglichkeit, ähnliche Funktionen auf der x86-Plattform zu implementieren. Auch wo wäre der beste Ort, um über solche Dinge zu erfahren (d. H. Gute Artikel / Websites / Foren für Lock / wartefreies Programmieren).
Bearbeiten
Ich denke, dass ich mehr Details geben muss, da angenommen wird, dass ich nur nach einer CAS-Operation (Vergleichen und Tauschen) suche. Was ich versuche, ist ein Lock-Free-Referenzzählsystem mit intelligenten Zeigern zu implementieren, auf die mehrere Threads zugreifen und diese ändern können. Ich brauche im Grunde eine Möglichkeit, die folgende Funktion auf einem x86-Prozessor zu implementieren.
Ich brauche wirklich etwas, das LWARX und STWCX ziemlich genau nachahmt, um das durchzuziehen (ich kann keinen Weg finden, dies mit dem CompareExchange zu tun, Funktionen zu tauschen oder hinzuzufügen, die ich bisher für das x86 gefunden habe) / p>
Danke
Wie Michael schon erwähnt hat, suchen Sie wahrscheinlich nach der Anweisung cmpxchg
.
Es ist jedoch wichtig darauf hinzuweisen, dass die PPC-Methode dies als Load Link / Store Conditional bezeichnet (LL / SC), während die x86-Architektur Compare And Swap (CAS) verwendet. LL / SC hat eine stärkere Semantik als CAS, da jede Änderung des Wertes an der konditionierten Adresse dazu führt, dass der Speicher fehlschlägt, selbst wenn die andere Änderung den Wert mit dem gleichen Wert ersetzt, auf den die Last konditioniert wurde. CAS hingegen würde in diesem Fall Erfolg haben. Dies ist bekannt als das ABA-Problem (siehe CAS-Link für weitere Informationen).
Wenn Sie die stärkere Semantik für die x86-Architektur benötigen, können Sie sie mithilfe der x86s-Anweisung " cmpxchg8b
" oder " cmpxchg16b
" unter x86_64 mit doppelter Breite vergleichen und austauschen (DWCAS). Auf diese Weise können Sie zwei aufeinander folgende Wörter mit "natürlicher Größe" auf einmal austauschen, anstatt nur die übliche. Der Grundgedanke ist, dass eines der beiden Wörter den Wert des Interesses enthält und das andere eine immer steigende "Mutationsanzahl" enthält. Obwohl dies das Problem technisch nicht beseitigt, ist die Wahrscheinlichkeit, dass die Mutation zwischen den Versuchen hin- und herwechselt, so gering, dass sie für die meisten Zwecke ein vernünftiger Ersatz ist.
x86 unterstützt nicht direkt "optimistic concurrency" wie PPC - stattdessen basiert x86's Unterstützung für Parallelität auf einem "lock prefix", siehe hier . (Einige sogenannte "atomare" Befehle, wie XCHG, erhalten ihre Atomarität, indem sie das LOCK-Präfix intrinsisch aktivieren, unabhängig davon, ob der Assemblercode-Programmierer es tatsächlich codiert hat oder nicht). Es ist nicht genau "bombensicher", um es diplomatisch zu formulieren (es ist tatsächlich eher unfallträchtig, würde ich sagen ;-)).
Sie suchen wahrscheinlich nach der Befehlsfamilie cmpxchg.
Sie müssen diesen Anweisungen eine Lock-Anweisung voranstellen, um gleiches Verhalten zu erhalten.
Schauen Sie hier nach schneller Überblick über das, was verfügbar ist.
Sie werden wahrscheinlich mit etwas ähnlichem enden:
%Vor%Sie sollten dieses Papier ...
Bearbeiten
Als Reaktion auf die aktualisierte Frage möchten Sie etwas wie die Boost shared_ptr ? Wenn ja, schauen Sie sich den Code und die Dateien in diesem Verzeichnis an - sie werden Sie auf jeden Fall weiterbringen.
Was Sie versuchen zu tun, wird nicht so funktionieren, wie Sie es erwarten. Was Sie oben implementiert haben, können Sie mit der InterlockedIncrement-Funktion (Win32-Funktion; Assembly: XADD) durchführen.
Der Grund, warum Ihr Code nicht das tut, was Sie denken, ist, dass ein anderer Thread den Wert zwischen dem zweiten Lesen von * ptr und stwcx noch ändern kann, ohne den stwcx zu entwerten.
Weiß nicht, ob LWARX und STWCX die gesamte Cache-Zeile ungültig machen, CAS und DCAS tun dies. Das heißt, wenn Sie nicht viel Speicher (64 Bytes für jeden unabhängigen "abschließbaren" Zeiger) wegwerfen wollen, werden Sie nicht viel Verbesserung sehen, wenn Sie Ihre Software wirklich in Stress versetzen. Die besten Ergebnisse, die ich bis jetzt gesehen habe, waren, als Leute bewusst 64b kassierten, ihre Strukturen um sie herum planten (Sachen packten, die nicht strittig sind), alles auf 64b-Grenzen ausgerichtet hielten und explizite Lese- und Schreib-Datenbarrieren benutzten. Cache Line Invalidation kann ca. 20 bis 100 Zyklen kosten, was es zu einem größeren echten Perf-Problem macht, nur die Vermeidung von Sperren.
Sie müssen auch eine andere Speicherzuweisungsstrategie planen, um entweder kontrolliertes Lecken zu verwalten (wenn Sie Code in logische "Anfrageverarbeitung" partitionieren können - eine Anfrage "leckt" und dann am Ende alle Speichermasse freigibt) oder Dateiled Allocation Management, so dass eine Struktur, die sich in Konkurrenz befindet, niemals Speicher erhält, der durch Elemente der gleichen Struktur / Sammlung wieder freigegeben wurde (um ABA zu verhindern). Einige davon können sehr kontraintuitiv sein, aber es ist entweder das oder der Preis für GC.
Tags und Links multithreading x86 low-level reference-counting