Verwendung von volatile (Thread.VolatileRead / Thread.VolatileWrite) in C #

8

In einem Multithreaded-Programm, das auf einer Multi-CPU-Maschine läuft, muss ich auf den freigegebenen Zustand (_data im folgenden Beispielcode) zugreifen, indem ich flüchtige Lese- / Schreibvorgänge verwende, um die Korrektheit sicherzustellen.

Mit anderen Worten, können Heap-Objekte auf der CPU zwischengespeichert werden?

Im folgenden Beispiel und unter der Annahme, dass Multi-Threads auf die Methoden GetValue und Add zugreifen, benötige ich ThreadA, um Daten hinzufügen zu können (mithilfe der Add-Methode) und ThreadB, um die hinzugefügten Daten sofort anzeigen zu können die GetValue-Methode). Muss ich flüchtige Lese- / Schreibvorgänge zu _data hinzufügen, um dies sicherzustellen? Im Grunde will ich keine Daten hinzufügen, die auf der CPU von ThreadA zwischengespeichert werden.

/ Ich sperre nicht (exclusiven Thread-Zugriff erzwingen), da der Code extrem schnell sein muss und ich keine Daten aus _data entferne, also muss ich _data nicht sperren.

Danke.

**** Aktualisierung ****************************

Offensichtlich denkt ihr, dass das Lock-free-Fahren mit diesem Beispiel eine schlechte Idee ist. Aber welchen Nebenwirkungen oder Ausnahmen könnte ich hier begegnen?

Kann der Dictionary-Typ eine Ausnahme auslösen, wenn ein Thread die Werte zum Lesen iteriert und ein anderer Thread die Werte für die Aktualisierung iteriert? Oder würde ich nur "Dirty Reads" erleben (was in meinem Fall in Ordnung wäre)?

**** End Update ****************************

%Vor%

Danke für die Antworten. Was die Sperren anbelangt, so werden die Methoden ziemlich oft von mehreren Threads aufgerufen, sodass mein Problem bei umkämpften Sperren nicht die eigentliche Sperroperation ist.

Also meine Frage ist über CPU-Caching, können Heap-Objekte (die _Data-Instanz Feld) auf einer CPU zwischengespeichert werden? Benötige ich den Zugriff auf das _data-Feld mit volatilen Lese- / Schreibvorgängen?

/ Ich stehe auch bei .Net 2.0 fest.

Danke für Ihre Hilfe.

    
casperOne 08.12.2008, 11:07
quelle

6 Antworten

16

Die MSDN-Dokumentation für Dictionary<TKey, TValue> gibt an, dass sie für mehrere Leser sicher ist aber sie geben nicht die "ein Schreiber, mehrere Leser" garantieren, dass einige andere Klassen tun. Kurz gesagt, ich würde das nicht tun.

Sie sagen, Sie vermeiden das Sperren, weil Sie den Code "ultraschnell" brauchen - haben Sie versucht zu sperren, um zu sehen, wie hoch der Aufwand ist? Unangefochtene Schlösser sind sehr billig, und wenn das Schloss umkämpft ist, profitiert man von der zusätzlichen Sicherheit. Ich würde dies sicherlich ausführlich beschreiben, bevor ich mich dazu entscheide, mich um die Nebenläufigkeitsprobleme einer Lock-Free-Lösung zu kümmern. ReaderWriterLockSlim kann nützlich sein, wenn Sie tatsächlich mehrere Leser haben, aber es klingt, als ob Sie einen einzelnen Leser und einen einzigen Schreiber haben, zumindest im Moment - einfaches Sperren ist in diesem Fall einfacher.

    
Jon Skeet 08.12.2008 11:26
quelle
6

Ich denke, Sie missverstehen möglicherweise die Verwendung des volatile -Schlüsselwortes (entweder das oder ich, und jemand, bitte, fühlen Sie sich frei, mich zu korrigieren). Das Schlüsselwort volatile garantiert, dass Operationen zum Abrufen und Festlegen von Werten für den Wert der Variablen selbst aus mehreren Threads immer dieselbe Kopie verwenden. Wenn ich zum Beispiel einen bool habe, der einen Zustand angibt, dann wird der neue Wert sofort für den anderen verfügbar gemacht, wenn er in einem Thread gesetzt wird.

Sie ändern jedoch niemals den Wert Ihrer Variablen (in diesem Fall eine Referenz). Sie manipulieren nur den Speicherbereich, auf den die Referenz verweist. Wenn ich es als volatile readonly deklariere (was, wenn mein Verständnis vernünftig ist, den Zweck von volatile vereitelt, indem ich nie erlaube, dass es gesetzt wird), hat das keine Auswirkungen auf die tatsächlichen Daten, die manipuliert werden (der Backend-Speicher für die% Code%).

Alles, was gesagt wird, müssen Sie in diesem Fall wirklich eine Sperre verwenden. Ihre Gefahr geht über die Aussicht auf "Dirty Reads" hinaus (was bedeutet, dass das, was Sie gelesen haben, wäre zu irgendeinem Zeitpunkt gültig gewesen) in wirklich unbekanntes Gebiet. Wie Jon sagte, Sie brauchen wirklich den Beweis, dass das Sperren eine inakzeptable Leistung erzeugt, bevor Sie versuchen, die Straße der Lockless-Codierung zu gehen. Ansonsten ist das der Inbegriff einer vorzeitigen Optimierung.

    
Adam Robinson 01.06.2009 18:36
quelle
3

Das Problem ist, dass Ihre Add-Methode:

%Vor%

Könnte dazu führen, dass _data entscheidet, die Daten, die es enthält, vollständig neu zu organisieren - zu diesem Zeitpunkt könnte eine GetVaule-Anfrage auf irgendeine mögliche Weise fehlschlagen.

Sie benötigen eine Sperre oder eine andere Datenstruktur / Datenstrukturimplementierung.

    
Douglas Leeder 08.12.2008 12:31
quelle
2

Ich glaube nicht, dass volatile ein Ersatz für Sperren sein kann, wenn Sie Methoden aufrufen. Sie garantieren, dass der Thread A und der Thread B die gleiche Kopie des Wörterbuchs sehen, Sie aber trotzdem gleichzeitig auf das Wörterbuch zugreifen können. Sie können Multi-Moded-Sperren verwenden, um die Parallelität zu erhöhen. Siehe ReaderWriterLockSlim zum Beispiel.

  

Stellt eine Sperre dar, die verwendet wird   den Zugriff auf eine Ressource verwalten,   mehrere Threads zum Lesen oder   exklusiver Zugang zum Schreiben.

    
Eugene Yokota 08.12.2008 11:25
quelle
1

Beim Schlüsselwort volatile geht es nicht um das Sperren. Es wird verwendet, um anzuzeigen, dass der Wert des angegebenen Felds möglicherweise von einem anderen Thread oder einer anderen Sache geändert oder gelesen wird, die gleichzeitig mit Ihrem Code ausgeführt werden kann. Dies ist für den Compiler wichtig, da viele Optimierungsprozesse das Zwischenspeichern des Variablenwerts und das Neuanordnen der Anweisungen beinhalten. Das Schlüsselwort volatile weist den Compiler an, "vorsichtig" zu sein, wenn die Anweisungen optimiert werden, die auf volatile Variable verweisen.

Für die Verwendung von mehreren Threads im Wörterbuch gibt es viele Möglichkeiten. Der einfachste Weg ist die Verwendung von lock keyword, das über eine angemessene Leistung verfügt. Wenn Sie eine höhere Leistung benötigen, müssen Sie möglicherweise Ihr eigenes Wörterbuch für Ihre spezifische Aufgabe implementieren.

    
tia 25.09.2010 05:18
quelle
0

Volatile sperrt nicht, es hat nichts mit der Synchronisation zu tun. Lock-Free-Lesevorgänge bei schreibgeschützten Daten sind im Allgemeinen sicher. Beachten Sie, dass Sie anscheinend _data.Add () aufrufen, nur weil Sie nichts aus _data entfernen. Das ist NICHT schreibgeschützt. Also ja, dieser Code wird in einer Vielzahl von aufregenden und schwer vorhersehbaren Wegen in deinem Gesicht explodieren.

Verwenden Sie Sperren, es ist einfach, es ist sicherer. Wenn du ein Lock-Free-Guru bist (du bist es nicht!), Zeigt das AND-Profiling einen Engpass im Zusammenhang mit der Sperre, UND du kannst die Streitfragen nicht durch Partitionierung oder Wechsel zu Spin-Locks lösen DANN UND NUR DANN kannst du Untersuchen Sie eine Lösung, um blockierungsfreie Lesevorgänge zu erhalten, was bedeutet, dass Sie Ihr eigenes Wörterbuch von Grund auf neu schreiben müssen und schneller sein können als die Sperrlösung.

Fangen Sie an zu sehen, wie weit Sie von Ihrem Denken entfernt sind? Benutze einfach ein verdammtes Schloss!

    
Eloff 18.02.2010 18:20
quelle

Tags und Links