Ich habe eine Variable, mit der ich den Zustand darstelle. Es kann aus mehreren Threads gelesen und beschrieben werden.
Ich benutze Interlocked.Exchange
und Interlocked.CompareExchange
um es zu ändern. Ich lese es jedoch aus mehreren Threads.
Ich weiß, dass volatile
dies verwendet werden kann, um sicherzustellen, dass die Variable nicht lokal zwischengespeichert wird, sondern immer direkt aus dem Speicher liest.
Wenn ich die Variable jedoch auf flüchtig setze, wird eine Warnung über die Verwendung von flüchtig und die Übergabe mit ref an die Interlocked-Methoden generiert.
Ich möchte sicherstellen, dass jeder Thread den neuesten Wert der Variablen liest und nicht eine zwischengespeicherte Version, aber ich kann flüchtig nicht verwenden.
Es gibt ein, Interlocked.Read
aber es ist für 64-Bit-Typen und ist auf dem kompakten Framework nicht verfügbar. Die Dokumentation dazu besagt, dass es für 32-Bit-Typen nicht benötigt wird, da sie bereits in einer einzelnen Operation ausgeführt werden.
Über das Internet werden Aussagen gemacht, dass Sie nicht flüchtig sind, wenn Sie die Interlocked-Methoden für Ihren gesamten Zugriff verwenden. Sie können jedoch keine 32-Bit-Variable mit den Interlocked-Methoden lesen, sodass Sie Interlocked-Methoden auf keinen Fall für Ihren gesamten Zugriff verwenden können.
Gibt es eine Möglichkeit, das thread-sichere Lesen und Schreiben meiner Variablen ohne Verwendung der Sperre zu erreichen?
lock
und ich kann keine Referenz finden, die solche Garantien gibt.Antworten:
Sie können diese Warnung ignorieren, wenn Sie
Interlocked.Xxx
Funktionen verwenden (siehe diese Frage ), da diese immer flüchtige Operationen ausführen. Einevolatile
Variable ist also für den gemeinsam genutzten Status vollkommen in Ordnung. Wenn Sie um jeden Preis loswerden der Warnung möchten, können Sie tatsächlich kann eine verriegelte Lese tun mitInterlocked.CompareExchange (ref counter, 0, 0)
.Bearbeiten: Tatsächlich benötigen Sie
volatile
Ihre Statusvariable nur, wenn Sie direkt darauf schreiben möchten (dh nicht verwendenInterlocked.Xxx
). Wie von jerryjvl erwähnt , wird beim Lesen einer Variablen, die mit einer ineinandergreifenden (oder flüchtigen) Operation aktualisiert wurde, der neueste Wert verwendet.quelle
CompareExchange
wird ersetzt werden ,0
mit ,0
wenncounter
ist0
- dh ein No-op.volatile
variablen Person vor einer Optimierung durch den Compiler oder die JIT geschützt? Ist die Bearbeitung, die sich auf @jerryjvl bezieht, nicht falsch?Interlocked Operations und Volatile sollten eigentlich nicht gleichzeitig verwendet werden. Der Grund, warum Sie eine Warnung erhalten, ist, dass sie (fast?) Immer anzeigt, dass Sie falsch verstanden haben, was Sie tun.
Übermäßiges Vereinfachen und Paraphrasieren:
volatile
Gibt an, dass jeder Lesevorgang erneut aus dem Speicher gelesen werden muss, da möglicherweise andere Threads die Variable aktualisieren. Wenn dies auf ein Feld angewendet wird, das von der Architektur, auf der Sie ausgeführt werden, atomar gelesen / geschrieben werden kann, sollte dies alles sein, was Sie tun müssen, es sei denn, Sie verwenden long / ulong. Die meisten anderen Typen können atomar gelesen / geschrieben werden.Wenn ein Feld nicht als flüchtig markiert ist, können Sie
Interlocked
Operationen verwenden, um eine ähnliche Garantie zu geben, da dadurch der Cache geleert wird, sodass das Update für alle anderen Prozessoren sichtbar ist. Dies hat den Vorteil, dass Sie den Overhead übernehmen das Update eher als das Lesen.Welcher dieser beiden Ansätze am besten funktioniert, hängt davon ab, was genau Sie tun. Und diese Erklärung ist eine grobe Übervereinfachung. Daraus sollte jedoch klar sein, dass es sinnlos ist, beides gleichzeitig zu tun.
quelle
volatile
dass diesvolatile
kein Teil des Typsystems ist und der Angerufene, der die Referenz erhält, nicht weiß, dass die referenzierte Variable einen flüchtigen Zugriff benötigt.