2008-12-28 6 views
8

Ich habe eine Referenz-Typ-Variable, die readonly ist, weil die Referenz nie ändern, nur seine Eigenschaften. Als ich versuchte, den Modifikator volatile hinzuzufügen, warnte mich der kompilierte, dass es nicht beide Modifikatoren auf die gleiche Variable anwenden lassen würde. Aber ich denke, ich brauche es, um flüchtig zu sein, weil ich keine Cache-Probleme haben will, wenn ich seine Eigenschaften lese. Fehle ich etwas? Oder ist der Compiler falsch?Warum schreibgeschützte und flüchtige Modifikatoren sich gegenseitig ausschließen?

Aktualisierung Wie Martin in einem der folgenden Kommentare erklärte: Sowohl readonly als auch volatile Modifier gelten nur für die Referenz und nicht für die Eigenschaften des Objekts im Falle von Objekten vom Referenztyp. Das habe ich vermisst, also hat der Compiler Recht.

class C 
{ 
    readonly volatile string s; // error CS0678: 'C.s': a field cannot be both volatile and readonly 
} 
+0

Der Compiler ist [möglicherweise falsch] (http://stackoverflow.com/q/39004125/1149773) (obwohl möglicherweise nicht für Ihr spezielles Szenario). – Douglas

Antwort

14

Weder die readonly noch volatile Modifikatoren sind penetrativ. Sie beziehen sich auf die Referenz selbst, nicht auf die Eigenschaften des Objekts.

Das Schlüsselwort readonly bestätigt und erzwingt, dass eine Variable nach der Initialisierung nicht geändert werden kann. Die Variable ist der kleine Teil des Speichers, in dem die Referenz gespeichert ist.

Das Schlüsselwort volatile teilt dem Compiler mit, dass der Inhalt einer Variablen möglicherweise von mehreren Threads geändert wird. Dies verhindert, dass der Compiler Optimierungen (z. B. das Lesen des Werts der Variablen in ein Register und die Verwendung dieses Werts über mehrere Anweisungen) verwendet, die Probleme beim gleichzeitigen Zugriff verursachen könnten. Dies betrifft wiederum nur den kleinen Teil des Speichers, in dem die Referenz gespeichert ist.

Auf diese Weise können Sie sehen, dass sie sich gegenseitig ausschließen. Wenn etwas nur gelesen wird (kann nur einmal geschrieben werden, bei der Initialisierung oder Konstruktion), dann kann es auch nicht flüchtig sein (kann jederzeit von mehreren Threads beschrieben werden).


Wie für Ihre Besorgnis über Caching-Probleme, IIRC gibt es ziemlich strenge Regeln über, wenn der Compiler das Ergebnis einer Eigenschaft Aufruf cachen kann. Denken Sie daran, dass es ein Methodenaufruf ist, und es ist eine ziemlich schwere Optimierung (vom Standpunkt des Compilers), seinen Wert zwischenzuspeichern und überspringen, es wieder aufzurufen. Ich denke nicht, dass es etwas ist, worüber du dich zu sehr kümmern musst.

+1

Die Eigenschaften können nicht zwischengespeichert werden (ich weiß es nicht), aber die Hintergrundfelder sind definitiv. Die Felder sollten als flüchtig gekennzeichnet sein. – configurator

+0

Diese Antwort behandelt die Frage des OP korrekt, enthält jedoch eine irreführende Aussage: "Das Schlüsselwort volatile sagt dem Compiler, dass der Inhalt einer Variablen von mehreren Threads geändert werden kann." Das ist nur teilweise richtig; Das Schlüsselwort volatile teilt dem Compiler außerdem mit, dass der Inhalt einer Variablen von mehreren Threads gleichzeitig * geändert oder gelesen werden kann, auch wenn die Änderung nur einmal ausgeführt wird. Ich habe hier eine ähnliche Frage gestellt, die dieses Problem abdeckt: [C# Sprachfehler: volatile und readonly sollten sich nicht gegenseitig ausschließen] (http://stackoverflow.com/q/39004125/1149773). – Douglas

+0

Ich glaube nicht, dass meine Aussage irreführend ist. Vielleicht wäre es präziser zu sagen, dass es dem Compiler sagt, dass der Wert einer Variablen von anderen Threads geändert werden kann, während ein Thread sie liest, aber ich denke, dass * diese Phrasierung ohne weitere Erklärung irreführender ist, als dies implizieren könnte 'volatile' ist alles, was nötig ist, um eine Thread-Synchronisation bereitzustellen. Ich denke, mein Wortlaut erklärt das Konzept klar und der nächste Satz bietet genügend Details für ein grundlegendes Verständnis. Ihr Problem ist eine interessante Untersuchung des .NET-Initialisierungsverhaltens, die jedoch nicht davon ablenkt. –

1

Ein schreibgeschütztes Feld kann nur geschrieben werden, wenn das Objekt zuerst konstruiert wird. Daher wird auf der CPU kein Caching-Problem auftreten, da das Feld unveränderbar ist und sich nicht ändern kann.

+0

Ich verstehe Ihre Logik, aber ich stimme nicht zu. Ein Objekt kann nur gelesen werden und ändert sich immer noch durch seine Eigenschaften, da seine Eigenschaften nicht gelesen werden. Die Eigenschaft readonly verhindert in diesem Fall nur, dass die Variable einem anderen Objekt zugewiesen wird. Zumindest habe ich das verstanden, was ich gelernt habe. –

+2

@Vernict: Die readonly und volatile Modifier schützen nur die Referenz (oder den Wert im Falle atomarer Werte wie bool, int), nicht den Inhalt des Objekts! Das ist eine ganz andere Sache. –

0

Während die Referenz selbst Thread-sicher sein kann, sind ihre Eigenschaften möglicherweise nicht. Denken Sie darüber nach, was passieren würde, wenn zwei Threads gleichzeitig versuchen würden, eine innerhalb Ihres Referenzobjekts zu durchlaufen.

+0

Aber das ist etwas, gegen das weder schreibgeschützt noch flüchtig geschützt werden soll. Das müssen Sie sowieso mit der Synchronisation lösen. –

+0

@Charlie, Sie sagen, dass, selbst wenn das Objekt flüchtig ist, es nicht garantiert, dass seine Eigenschaften volatil sind? –

+0

@Martin C, sehr wahr. @Vernicht, wie ich es verstehe, ja. Sie müssen sicherstellen, dass Ihre Felder und Eigenschaften Thread-sicher sind. –

Verwandte Themen