Threading & implizite Speicherbarrieren

8

Versuchen, das Speichermodell von .net beim Threading zu verstehen. Diese Frage ist streng theoretisch und ich weiß, dass sie auf andere Weise aufgelöst werden kann, wie zum Beispiel die Verwendung einer Sperre oder das Markieren von _task als flüchtig.

Nehmen Sie den folgenden Codeabschnitt zum Beispiel:

%Vor%

Machen Sie nun die folgenden Annahmen: 1) Run kann mehrere Male (von verschiedenen Threads) aufgerufen werden und wird nie aufgerufen, nachdem Dispose aufgerufen wurde. 2) Dispose wird genau einmal aufgerufen.

Nun zu meiner Frage: Wird der Wert von _task (in der Dispose-Methode) immer ein "frischer" Wert sein, dh wird er aus dem "Hauptspeicher" gelesen und nicht aus einem Register gelesen? Von dem, was ich gelesen habe Interlocked erstellt eine vollständige Zaun Speicherbarriere, also gehe ich davon aus, _task wird aus dem Hauptspeicher gelesen werden oder bin ich komplett ausgeschaltet?

    
Tsef 26.05.2014, 14:31
quelle

2 Antworten

1

Abgesehen von den Feinheiten, die Phrase "Fresh Read" zu verwenden, wird ja auch _task aus dem Hauptspeicher zurückgewonnen. Es kann jedoch getrennte und noch subtilere Probleme mit Ihrem Code geben. Betrachten Sie eine alternative, aber exakt äquivalente Struktur für Ihren Code, die es leichter machen sollte, das potenzielle Problem zu erkennen.

%Vor%

Der zweite Parameter von CompareExchange wird als Wert übergeben, damit er in einem Register zwischengespeichert werden kann. Ich stelle mir folgendes Szenario vor.

  • Thread A ruft Run
  • auf
  • Thread A macht etwas anderes mit _working , was bewirkt, dass es in einem Register zwischengespeichert wird.
  • Thread B schließt die Aufgabe ab und ruft Exchange vom Delegierten ContinueWith auf.
  • Thread A ruft Dispose .
  • auf

Im obigen Szenario würde sich _working zu 1 und dann zu 0 ändern, gefolgt von Dispose , um es auf eine 1 zurückzusetzen (weil dieser Wert in einem Register zwischengespeichert wurde), ohne in die if -Anweisung zu gehen. An diesem Punkt könnte sich _working in einem inkonsistenten Zustand befinden.

Ich persönlich denke, dass dieses Szenario höchst unwahrscheinlich ist, hauptsächlich weil ich nicht denke, dass _working auf diese Weise zwischengespeichert wird, besonders wenn Sie immer darauf achten, die Zugriffe darauf mit Interlock-Operationen zu schützen.

Wenn nichts anderes, hoffe ich, gibt es Ihnen Denkanstöße in Bezug auf komplizierte Lock-Free-Techniken.

    
Brian Gideon 29.05.2014, 19:17
quelle
1

Ich code nicht in C #, aber wenn volle Speicherbarriere verwendet wird, dann ist Ihre Interpretation korrekt. Der Compiler sollte einen in Registern gespeicherten Wert nicht erneut verwenden, sondern ihn so abrufen, dass Speicherordnungsbarrieren den tatsächlichen Wert im Speichersubsystem nicht maskieren.

Ich habe auch diese Antwort gefunden, die klar erklärt, dass dies in der Tat der Fall ist, also scheint die Dokumentation, die Sie gelesen haben, korrekt zu sein: Verwendet Interlocked.CompareExchange eine Speicherbarriere?

    
Alexandros 27.05.2014 01:16
quelle