2015-05-16 3 views
6

Ich verstehe das Stichwort in C++ ziemlich gut. Aber in C# scheint es eine andere Bedeutung zu haben, mehr im Zusammenhang mit Multi-Threading. Ich dachte, Bool-Operationen seien atomar, und ich dachte, wenn die Operation atomar wäre, hätten Sie keine Bedenken. Was vermisse ich?Warum sollte ein Bool beim Multithreading in C# volatil werden?

https://msdn.microsoft.com/en-us/library/x13ttww7.aspx

+1

'volatile' verhindert das Neuanordnen von Befehlen um den Variablenzugriff. Es ist ziemlich komplex. Siehe http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility – xanatos

+0

[Eric Lipperts Antwort auf eine andere Frage] (http://Stackoverflow.com/a/26315297/517852) hat eigentlich eine sehr gute Beschreibung des Unterschiede in der Semantik von flüchtigen zwischen C++ und C#. –

Antwort

3

Das Schlüsselwort volatile in C# dreht sich alles um Lesen/Schreiben Neuordnung, also ist es etwas ziemlich esoterisch.

http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility

(das halte ich über Einfädeln eines der „Bibeln“ sein) schreibt:

Das Schlüsselwort volatile den Compiler weist einen Belegungs-Zaun auf jedem aus diesem Feld lesen zu erzeugen und einen Freigabefaktor bei jedem Schreiben in dieses Feld.Ein Acquire-Fence verhindert, dass andere Lese-/Schreibvorgänge vor dem Zaun verschoben werden; Ein Freigabezaun verhindert, dass andere Lese-/Schreibvorgänge nach dem Zaun verschoben werden. Diese "Halbzäune" ​​sind schneller als Vollzäune, weil sie der Laufzeit und der Hardware mehr Spielraum für Optimierungen geben.

Es ist etwas ganz unlesbar :-)

Jetzt ... Was es bedeutet nicht:

  • Es bedeutet nicht, dass ein Wert wird jetzt/gelesen werden wird geschrieben werden jetzt

es bedeutet einfach, dass, wenn Sie etwas von einem flüchtigen Variable lesen, alles el se, die gelesen/geschrieben wurde, bevor dieser "spezielle" Lesevorgang nach diesem "speziellen" Lesevorgang verschoben wird. Es schafft also eine Barriere. Paradoxerweise garantieren Sie beim Lesen einer volatilen Variablen, dass alle Schreibvorgänge, die Sie mit einer anderen Variablen (flüchtig oder nicht) zum Zeitpunkt des Lesens gemacht haben, ausgeführt werden.

Ein flüchtiges Schreiben ist wahrscheinlich etwas wichtiger und wird zum Teil von der Intel-CPU garantiert, und etwas, das von der ersten Version von Java nicht garantiert wurde: keine Neuordnung des Schreibvorgangs. Das Problem war:

object myrefthatissharedwithotherthreads = new MyClass(5); 

wo

class MyClass 
{ 
    public int Value; 
    MyClass(int value) 
    { 
     Value = value; 
    } 
} 

Nun ..., dass die Expression vorstellen kann sein:

var temp = new MyClass(); 
temp.Value = 5; 
myrefthatissharedwithotherthreads = temp; 

wo temp etwas vom Compiler generiert wird, dass man‘ t sehen.

Wenn die Schreibvorgänge neu angeordnet werden können, könnten Sie haben:

var temp = new MyClass(); 
myrefthatissharedwithotherthreads = temp; 
temp.Value = 5; 

und ein anderer Thread eine teilweise initialisiert sehen konnte MyClass, da der Wert von myrefthatissharedwithotherthreads lesbar ist, bevor die Klasse MyClass Initialisierung beendet ist.

+1

Mehr als nur Zäune, "flüchtige" verhindert auch Optimierungen wie konstante Ausbreitung, Beseitigung von toten Code oder Registerhub. Es ist restriktiver als einfache Zäune um Zugriffe. –

+0

@Cicada Haben Sie eine Referenz für C#? – xanatos

+0

Nein, ich denke nicht, dass das im Standard ist. –

4

dachte ich Bool Operationen

Sie sind in der Tat Atomatom waren.

und ich dachte, dass, wenn die Operation atomar wäre, Sie keine Probleme haben würden.

Hier haben Sie ein unvollständiges Bild. Stellen Sie sich vor, Sie haben zwei Threads, die auf separaten Kernen mit jeweils eigenen Cache-Layern ausgeführt werden. Thread 1 hat foo in seinem Cache und Thread 2 aktualisiert den Wert foo. Thread # 1 wird die Änderung nicht sehen, es sei denn, foo wird als volatile markiert, eine lock erworben, die Interlocked Klasse verwendet oder explizit Thread.MemoryBarrier() genannt, was dazu führen würde, dass der Wert im Cache ungültig wird. guaranteeing that you read the most up to date value:

Mit dem flüchtigen Modifikator wird sichergestellt, dass ein Thread den aktuellsten Wert eines anderen Threads abruft.

Eric Lippert hat eine great post über Volatilität, wo er erklärt:

Die wahre Semantik von flüchtigen liest und schreibt sind wesentlich komplexer als ich hier skizziert habe; in Tatsache, dass sie nicht wirklich garantieren, dass jeder Prozessor stoppt, was es macht und aktualisiert Caches zu/vom Hauptspeicher. Eher bieten sie schwächere Garantien über , wie Speicherzugriffe vor und nach Lesevorgängen und Schreibvorgänge beobachtet werden können, in Bezug aufeinander geordnet werden.

Edit:

Per @xanatos Kommentar Dieses nicht bedeutet, dass volatile garantiert eine sofortige Lese garantiert er einen Read auf den aktualisierten Wert.

+0

Teilweise falsch. Ein "flüchtiger" Schreibvorgang garantiert keinen sofortigen Schreibvorgang. – xanatos

+0

@xanatos Ich meinte nicht, dass es unmittelbare Schreibvorgänge garantiert. Ich garantiere ein Lesen des aktualisierten Wertes. –

+0

Sie haben Probleme beim Schreiben von 'volatile' :-) Zweimal geschrieben, zweimal falsch :-) :-) – xanatos

Verwandte Themen