Gibt es einen Vorteil der Verwendung von volatilen Schlüsselwörtern im Gegensatz zur Verwendung der Interlocked-Klasse?

8

Mit anderen Worten, kann ich etwas mit einer volatilen Variablen machen, die nicht auch mit einer normalen Variablen und der Interlocked-Klasse gelöst werden kann?

    
codymanix 09.11.2009, 14:15
quelle

5 Antworten

15

EDIT: Frage weitgehend neu geschrieben

Um diese Frage zu beantworten, bin ich in der Sache ein bisschen weiter getaucht und habe ein paar Dinge über volatile und Interlocked herausgefunden, die mir nicht bekannt waren. Lasst uns das klären, nicht nur für mich, sondern auch für diese Diskussion und andere Leute, die darüber nachlesen:

  • volatile read / write soll immun gegen Neuordnung sein. Das only bedeutet Lesen und Schreiben, nicht bedeutet keine andere Aktion;
  • Volatilität wird nicht auf der CPU erzwungen, d. h. Hardwareebene (x86 verwendet Zäune erwerben und freigeben auf beliebige Lesen / Schreiben). Es verhindert Compiler- oder CLR-Optimierungen;
  • Interlocked verwendet atomare Assemblerbefehle für CompareExchange ( cmpxchg ), Inkrement ( inc ) etc;
  • Interlocked verwendet manchmal eine Sperre: Hardware-Sperre aktiviert Multiprozessorsysteme ; In Uni-Prozessor-Systemen gibt es keine Hardware-Sperre;
  • Interlocked unterscheidet sich von volatile dadurch, dass es eine vollständige Fence verwendet, wobei volatile einen halben Zaun verwendet.
  • Ein Lesevorgang nach einem Schreibvorgang kann neu geordnet werden , wenn Sie volatile verwenden. Es kann nicht mit Interlocked passieren. VolatileRead und VolatileWrite haben das gleiche Umsortierungsproblem wie 'volatile (Link dank Brian Gideon).

Nachdem wir nun die Regeln haben, können wir eine Antwort auf Ihre Frage definieren:

  • Technisch: Ja, es gibt Dinge, die Sie mit volatile tun können, was Sie mit Interlocked nicht tun können:
    1. Syntax: Sie können nicht a = b schreiben, wobei a oder b flüchtig ist, aber das ist offensichtlich;
    2. Sie können einen anderen Wert lesen, nachdem Sie ihn aufgrund einer Neuordnung in eine flüchtige Variable geschrieben haben. Dies ist mit Interlocked nicht möglich. Mit anderen Worten: Sie können less sicher mit volatile sein, dann können Sie mit Interlocked .
    3. arbeiten
    4. Leistung: volatile ist schneller als Interlocked .
  • Semantisch: Nein, weil Interlocked einfach eine Obermenge von Operationen liefert und sicherer zu verwenden ist, da es sich um vollständiges Fencing handelt. Sie können nichts mit volatile tun, was Sie mit Interlocked nicht tun können und Sie können viel mit Interlocked machen, was Sie nicht mit volatile tun können:

    %Vor%
  • Gültigkeitsbereich: Ja, wenn eine Variable volatile deklariert wird, wird sie für jeden einzelnen Zugriff volatil. Es ist unmöglich, dieses Verhalten auf andere Weise zu erzwingen, daher kann volatile nicht durch Interlocked ersetzt werden. Dies ist in Szenarien erforderlich, in denen andere Bibliotheken, Schnittstellen oder Hardware auf Ihre Variable zugreifen und diese jederzeit aktualisieren können oder die neueste Version benötigen.

Wenn Sie mich fragen, ist dieses letzte Bit der tatsächliche wirkliche Bedarf für volatile und macht es vielleicht ideal, wenn zwei Prozesse Speicher teilen und ohne Sperren lesen oder schreiben müssen. Das Deklarieren einer Variablen als volatile ist in diesem Kontext viel sicherer und erzwingt dann, dass alle Programmierer Interlocked verwenden (was Sie nicht vom Compiler erzwingen können).

BEARBEITEN: Das folgende Zitat war Teil meiner ursprünglichen Antwort, ich lasse es in; -)

Ein Zitat aus dem Standard C # Programmiersprache :

  

Für nichtflüchtige Felder, Optimierung   Techniken, die diese Nachbestellung berücksichtigen   Anweisungen können zu unerwarteten Ergebnissen führen   und unvorhersehbare Ergebnisse in   Multithread-Programme, auf die zugegriffen wird   Felder ohne Synchronisation wie z   das wird durch die lock-Anweisung bereitgestellt.   Diese Optimierungen können von durchgeführt werden   der Compiler, durch das Laufzeitsystem,   oder durch Hardware. Für flüchtige Felder,   solche Neuordnungsoptimierungen sind   eingeschränkt:

     
  • Ein Lesevorgang in einem flüchtigen Feld wird als flüchtiger Lesevorgang bezeichnet. Ein flüchtiges Lesen   hat: Semantik erwerben "; das ist es   ist garantiert vor jedem auftreten   Verweise auf Speicher, die danach auftreten   es in der Anweisungsfolge.

  •   
  • Ein Schreiben eines flüchtigen Felds wird als flüchtiges Schreiben bezeichnet. EIN   volatile write hat "release   Semantik ", das heißt, es ist garantiert   nach Speicherreferenzen passieren   vor dem Schreibbefehl in der   Anweisungsfolge.

  •   

Update: Frage wurde größtenteils neu geschrieben, korrigierte meine ursprüngliche Antwort und fügte eine "echte" Antwort hinzu

    
Abel 09.11.2009, 14:27
quelle
1

Das ist ein ziemlich komplexes Thema. Ich finde Joseph Albaharis writup als eine der definitiveren und genaueren Quellen für Multithreading-Konzepte in .NET Framework, das helfen könnte, Ihre Frage zu beantworten.

Aber um es kurz zusammenzufassen: Es gibt eine Menge Überschneidungen zwischen dem volatile Schlüsselwort und der Interlocked Klasse, soweit sie verwendet werden können. Und natürlich gehen beide weit darüber hinaus, was man mit einer normalen Variable machen kann.

    
Brian Gideon 09.11.2009 14:27
quelle
0

Ja - Sie können den Wert direkt ansehen.

Solange Sie nur die Interlocked-Klasse verwenden, um auf die Variable zuzugreifen, gibt es keinen Unterschied. Was volatile tut, ist, dass es dem Compiler sagt, dass die Variable speziell ist, und wenn sie optimiert wird, sollte nicht davon ausgegangen werden, dass sich der Wert nicht geändert hat.

Nimmt diese Schleife:

%Vor%

Wenn Sie in einem anderen Thread done auf true setzen, würden Sie erwarten, dass die Schleife beendet wird. Wenn dies jedoch nicht als volatile markiert ist, hat der Compiler die Option zu erkennen, dass der Schleifencode niemals done ändern kann und den Vergleich für den Exit optimieren kann.

Dies ist eines der schwierigen Dinge bei der Multithread-Programmierung - viele der Situationen, die Probleme sind, kommen nur in bestimmten Situationen vor.

    
Aaron 09.11.2009 14:27
quelle
0

Ich werde nicht versuchen, eine Autorität zu diesem Thema zu sein, aber ich würde Ihnen wärmstens empfehlen, einen Blick auf Dieser Artikel von dem gepriesenen Jon Skeet.

Sehen Sie sich auch den letzten Teil von diese Antwort an welche Details wofür volatile verwendet werden soll.

    
akmad 09.11.2009 14:29
quelle
-1

Ja, Sie können etwas Leistung erzielen, indem Sie eine volatile Variable anstelle einer Sperre verwenden.

Lock ist eine vollständige Speicherbarriere, die Ihnen die gleichen Eigenschaften einer flüchtigen Variablen wie viele andere geben kann. Wie bereits erwähnt, stellt volatile nur sicher, dass in Multi-Threaded-Szenarien, wenn eine CPU einen Wert in ihrer Cache-Zeile ändert, die anderen CPUs den Wert sofort sehen, aber überhaupt keine Locking-Semantik sicherstellen.

Die Sache ist Sperre ist viel mächtiger als flüchtig und Sie sollten flüchtig verwenden, wenn Sie können, um unnötige Sperren zu vermeiden.

    
Jorge Córdoba 09.11.2009 14:44
quelle