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; 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. 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:
volatile
tun können, was Sie mit Interlocked
nicht tun können:
a = b
schreiben, wobei a
oder b
flüchtig ist, aber das ist offensichtlich; Interlocked
nicht möglich. Mit anderen Worten: Sie können less sicher mit volatile
sein, dann können Sie mit Interlocked
. 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:
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
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.
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.
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.
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.
Tags und Links .net c# multithreading volatile interlocked