Es gibt einen sehr guten Artikel von Joe Albahari zu erklären volatile
in C#: Threading in C#: PART 4: ADVANCED THREADING.Volatile liest/schreibt und Befehl neu zu ordnen
Unter Berücksichtigung Anweisung Neuordnungs Joe verwendet dieses Beispiel:
public class IfYouThinkYouUnderstandVolatile
{
private volatile int x, y;
private void Test1() // Executed on one thread
{
this.x = 1; // Volatile write (release-fence)
int a = this.y; // Volatile read (acquire-fence)
}
private void Test2() // Executed on another thread
{
this.y = 1; // Volatile write (release-fence)
int b = this.x; // Volatile read (acquire-fence)
}
}
Im Grunde, was er sagt, ist, dass a
und b
beide mit 0
enthalten könnten am Ende, wenn die Verfahren auf verschiedene Threads parallel ausgeführt werden.
IOW der Optimierer oder Prozessor könnte die Anweisungen neu anordnen, wie folgt:
public class IfYouThinkYouUnderstandVolatileReordered
{
private volatile int x, y;
private void Test1() // Executed on one thread
{
int tempY = this.y; // Volatile read (reordered)
this.x = 1; // Volatile write
int a = tempY; // Use the already read value
}
private void Test2() // Executed on another thread
{
int tempX = this.x; // Volatile read (reordered)
this.y = 1; // Volatile write (release-fence)
int b = tempX; // Use the already read value
}
}
Der Grund, warum dies geschehen kann, obwohl wir volatile
verwenden, ist, dass ein Anweisung lesen kann nach einem Schreibbefehl bewegt werden vor der Schreibanweisung.
Bis jetzt verstehe ich, was hier passiert.
Meine Frage ist: könnte diese Neuordnung durch Stapelrahmen arbeiten? Ich meine, kann ein flüchtiger Schreibbefehl nach einem flüchtigen Lese-Befehl verschoben werden, der in einer anderen Methode (oder einem Eigenschafts-Accessor) passiert?
Sehen Sie sich den folgenden Code an: Er arbeitet mit Eigenschaften, anstatt direkt auf Instanzvariablen zuzugreifen.
Wie sieht es mit der Neuordnung in diesem Fall aus? Könnte es auf jeden Fall passieren? Oder könnte es nur passieren, wenn der Compiler den Zugriff auf die Eigenschaft inline ausführt?
public class IfYouThinkYouUnderstandVolatileWithProps
{
private volatile int x, y;
public int PropX
{
get { return this.x; }
set { this.x = value; }
}
public int PropY
{
get { return this.y; }
set { this.y = value; }
}
private void Test1() // Executed on one thread
{
this.PropX = 1; // Volatile write (release-fence)
int a = this.PropY; // Volatile read (acquire-fence)
}
private void Test2() // Executed on another thread
{
this.PropY = 1; // Volatile write (release-fence)
int b = this.PropX; // Volatile read (acquire-fence)
}
}
'volatile' stoppt nicht ** all ** die Neuordnung.Mit diesem Schlüsselwort können Operationen gleichen Typs immer noch neu geordnet werden (wie zwei Lesevorgänge vor dem Schreiben und zwei Schreibvorgänge vor dem Lesen). – VMAtm