2017-05-24 3 views
1

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) 
    } 
} 
+0

'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

Antwort

1

Sie sollten nicht über so hohe Ebenen Dinge denken, weil Sie sie nicht kontrollieren können. JIT hat viele Gründe zu inline oder nicht. Neuordnung ist ein gutes Konzept, das Ihnen erlaubt, über mögliche Ergebnisse der parallelen Codeausführung nachzudenken. Aber die wirklichen Dinge, die passieren, sind nicht nur das Umordnen von Lese-/Schreiboperationen. Es kann echte Neuordnung oder Zwischenspeicherung von Werten in CPU-Registern durch JIT oder Effekte spekulativer Ausführung durch die CPU selbst sein oder wie der Speichercontroller seine Aufgabe erfüllt.

Denken Sie an Lesen und Schreiben von Teilen des Gedächtnisses von Zeiger (oder weniger) Größe. Verwenden Sie die Neuordnung Modell von solchen Lese-und Schreibvorgängen und verlassen Sie sich nicht auf die heutigen Besonderheiten der JIT oder CPU, auf der Ihr Programm läuft.

1

Wie gesagt in ECMA-335

I.12.6.4 Optimization
Konforme Implementierungen der CLI sind freie Programme unter Verwendung jeder Technik auszuführen, die, in einem einzelnen Ausführungs-Thread gewährleistet, Die von einem Thread generierten Nebenwirkungen und Ausnahmen sind in der vom CIL angegebenen Reihenfolge sichtbar. Zu diesem Zweck stellen nur flüchtige Operationen (einschließlich flüchtiger Lesevorgänge) sichtbare Nebenwirkungen dar. (Beachten Sie, dass zwar nur flüchtige Vorgänge sichtbare Nebenwirkungen darstellen, flüchtige Vorgänge jedoch auch die Sichtbarkeit von nichtflüchtigen Referenzen beeinflussen.) Flüchtige Vorgänge sind in §I.12.6.7 angegeben.Es sind derzeit keine Bestellung Garantien in Bezug auf Ausnahmen in ein Gewinde eingespritzt von einem anderen Thread (solche Ausnahmen sind manchmal als „asynchrone Ausnahmen“ (zB System.Threading.ThreadAbortException).

Also, natürlich ist es erlaubt alle Inline dieser Code und dann ist es das gleiche wie es war

Verwandte Themen