Ist der Zugriff auf ein Bool- Feld in C # atomar? Muss ich insbesondere ein Schloss schließen:
class Foo
{
private bool _bar;
//... in some function on any thread (or many threads)
_bar = true;
//... same for a read
if (_bar) { ... }
}
Antworten:
Ja.
wie in C # Language Spec gefunden .
Bearbeiten: Es lohnt sich wahrscheinlich auch, das flüchtige Schlüsselwort zu verstehen .
quelle
Interlocked.Add(ref myInt);
z.i++
ist gleichi=i+1
, was bedeutet, dass Sie ein atomares Lesen, dann eine Addition und dann ein atomares Schreiben durchführen. Ein anderer Thread könntei
nach dem Lesen, aber vor dem Schreiben geändert werden. Zum Beispiel können zwei Threads, diei++
gleichzeitig auf demselben i arbeiten, gleichzeitig lesen (und somit denselben Wert lesen), einen hinzufügen und dann beide denselben Wert schreiben, wobei effektiv nur einmal hinzugefügt wird. Interlocked.Add verhindert dies. In der Regel ist die Tatsache, dass ein Typ atomar ist, nur dann nützlich, wenn nur ein Thread geschrieben wird, aber viele Threads gelesen werden.Wie oben erwähnt, ist bool atomar, aber Sie müssen sich immer noch daran erinnern, dass es auch davon abhängt, was Sie damit machen möchten.
ist keine atomare Operation, was bedeutet, dass sich der b-Wert ändern kann, bevor der aktuelle Thread den Code nach der if-Anweisung ausführt.
quelle
Bool-Zugriffe sind in der Tat atomar, aber das ist nicht die ganze Geschichte.
Sie müssen sich nicht um das Lesen eines Werts kümmern, der "unvollständig geschrieben" ist - es ist nicht klar, was dies möglicherweise für einen Bool bedeuten könnte -, aber Sie müssen sich um Prozessor-Caches kümmern, zumindest wenn Details von Timing sind ein Problem. Wenn Thread 1, der auf Kern A ausgeführt wird, Ihren
_bar
Cache hat und_bar
von Thread 2, der auf einem anderen Kern ausgeführt wird, aktualisiert wird, wird Thread 1 die Änderung nicht sofort sehen, es sei denn, Sie fügen Sperren hinzu, deklarieren_bar
alsvolatile
oder fügen explizit Aufrufe einThread.MemoryBarrier()
, um den zu ungültig zu machen zwischengespeicherter Wert.quelle
var fatObject = new FatObject(); Thread.MemoryBarrier(); _sharedRefToFat = fatObject;
Der Ansatz, den ich verwendet habe und den ich für richtig halte, ist
Das Ziel bestand im Wesentlichen darin, zu vermeiden, dass ein Objekt bei jeder Iteration wiederholt gesperrt werden muss, um zu überprüfen, ob es gesperrt werden muss, um eine große Menge an Statusänderungsinformationen bereitzustellen, die selten vorkommen. Ich denke, dieser Ansatz funktioniert. Und wenn absolute Konsistenz erforderlich ist, denke ich, dass Volatilität auf dem B- Bool angemessen wäre.
quelle
lock()
, brauchen Sie nichtvolatile
.