Ich habe in Jon's Skeet Online-Seite gelesen, wie man einen threadsicheren Singleton in C # erstellt
%Vor%Im Absatz unter diesem Code heißt es:
Wie oben angedeutet, ist das oben genannte nicht threadsicher. Zwei verschiedene Threads könnten beide den Test if (instance == null) und fand es wahr, dann erstellen beide Instanzen, die die Singleton-Muster. Beachten Sie, dass die Instanz möglicherweise bereits vorhanden ist wurde erstellt, bevor der Ausdruck ausgewertet wird, aber das Speichermodell garantiert nicht, dass der neue Wert der Instanz von anderen gesehen wird Threads, sofern nicht geeignete Speicherbarrieren übergeben wurden.
Können Sie bitte erklären, warum das Speichermodell nicht garantiert, dass der neue Wert der Instanz von anderen Threads erkannt wird?
Die statische Variable befindet sich auf dem Heap, aber warum wird sie nicht sofort mit anderen Threads geteilt? Müssen wir auf den Kontextwechsel warten, damit der andere Thread weiß, dass die Instanz nicht mehr null ist?
Können Sie bitte erklären, warum das Speichermodell nicht garantiert, dass der neue Wert der Instanz von anderen Threads gesehen wird?
Das Speichermodell ist komplex und im Moment nicht eindeutig dokumentiert, aber im Grunde gibt es nur wenige Situationen, in denen man sich sicher auf einen Wert verlässt, der von einem Thread geschrieben wird, der auf einem anderen Thread "gesehen" wird Inter-Thread-Kommunikation geht weiter.
Betrachten Sie zum Beispiel Folgendes:
%Vor% Wenn Sie zwei Threads erstellt haben, von denen einer TightLoop
aufruft und ein anderer Stop
aufruft, gibt es keine Garantie dafür, dass die Schleifenmethode jemals beendet wird.
In modernen CPUs gibt es viele Caching-Ebenen. Wenn jede Leseoperation in den Hauptspeicher zurückkehrt, werden viele Optimierungen entfernt. Also haben wir Speichermodelle, die garantieren, welche Änderungen in welchen Situationen definitiv sichtbar sein werden. Abgesehen von diesen Garantien darf der JIT-Compiler annehmen, dass es effektiv nur einen einzigen Thread gibt - also könnte er den Wert des Feldes in einem Register zwischenspeichern und zum Beispiel nie wieder den Hauptspeicher erreichen.
Das aktuell dokumentierte Speichermodell ist sehr unzureichend und würde vorschlagen , dass einige eindeutig seltsame Optimierungen gültig sein sollten. Ich würde zu auch nicht weit in diese Richtung gehen, aber es lohnt sich, Joe Duffys Blog-Post auf der CLR 2.0-Speichermodell . (Das ist stärker als das dokumentierte ECMA-Speichermodell, aber ein Blogpost ist nicht der ideale Ort für solch eine wichtige Dokumentation, und ich denke, dass noch mehr Klarheit benötigt wird.)
Die statische Variable befindet sich auf dem Heap, aber warum wird sie nicht mit anderen Threads geteilt?
Es ist mit anderen Threads geteilt - aber der Wert ist nicht unbedingt sofort sichtbar.
Können Sie bitte erklären, warum das Speichermodell nicht garantiert, dass der neue Wert der Instanz von anderen Threads gesehen wird?
Es gibt ein paar Probleme mit diesem Code. Weil der Variablen noch kein neuer Wert zugewiesen wurde. Zwischen dem Vergleich von Null ( if (instance==null)
) und der Zuweisung des neuen Wertes ( instance = new Singleton();
) kann einiges passieren.
Das Problem, auf das Sie verweisen, bezieht sich auf Speicher, der vom Prozessor zwischengespeichert wird. Die Variable ist weiterhin null
dort, aber bereits im Speicher durch die Zuweisung aus dem Code festgelegt. Es wird diesen zwischengespeicherten Speicher später aktualisieren.
Können Sie bitte erklären, warum ...
Weil es den JVM-Implementern ermöglicht, Ihnen eine JVM zur Verfügung zu stellen, die die bestmögliche Leistung auf einer Vielzahl verschiedener Computerarchitekturen erzielt.
Die effiziente und zuverlässige Kommunikation und gemeinsame Nutzung von Speichern zwischen Threads, die auf verschiedenen Prozessoren eines Multiprozessor-Computers ausgeführt werden, ist ein schwieriges Problem für die Entwickler von Computersystemen. Es gibt verschiedene Ansätze, und wenn ein Thread auf einem Prozessor eine gemeinsam genutzte Variable aktualisiert, kann ein Thread, der auf einem anderen Prozessor ausgeführt wird, nie die Aktualisierung sehen, wenn nicht beide Prozessoren spezielle Schritte ausführen Stellen Sie sicher, dass der neue Wert freigegeben ist.
Diese "speziellen Schritte" können teuer sein. Das Design der Java-Programmiersprache gibt JVM-Entwicklern die Möglichkeit, spezielle Schritte zu ergreifen, wenn sie benötigt werden, aber sie werden nicht gezwungen, diese Schritte auszuführen, wenn sie nicht benötigt werden.
Leider kann die JVM nicht immer wissen, welche Variablen geteilt werden und wann sie geteilt werden. Ein Teil der Verantwortung liegt also bei dir. Google für "Java Memory Model", um herauszufinden, was genau die Verantwortung des Java-Programmierers ist.
Tags und Links c# multithreading