2008-12-28 16 views
8

Tengo una variable de tipo de referencia que es readonly, porque la referencia nunca cambia, solo sus propiedades. Cuando traté de agregar el modificador volatile, el compilado me advirtió que no permitiría que los dos modificadores se aplicaran a la misma variable. Pero creo que necesito que sea volátil porque no quiero tener problemas de almacenamiento en caché al leer sus propiedades. ¿Me estoy perdiendo algo? ¿O el compilador está equivocado?¿Por qué los modificadores de lectura y volátiles son mutuamente excluyentes?

Actualización Como dijo Martin en uno de los comentarios a continuación: Los modificadores de solo lectura y volátiles se aplican solo a la referencia, y no a las propiedades del objeto, en el caso de los objetos de tipo referencia. Eso es lo que me faltaba, entonces el compilador tiene razón.

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

El compilador es [potencialmente incorrecto] (http://stackoverflow.com/q/39004125/1149773) (aunque posiblemente no sea para su caso particular). – Douglas

Respuesta

14

Ni los modificadores readonly ni volatile son penetrantes. Se aplican a la referencia en sí, no a las propiedades del objeto.

La palabra clave readonly afirma y hace cumplir que una variable no se puede cambiar después de la inicialización. La variable es el pequeño trozo de memoria donde se almacena la referencia.

La palabra clave volatile le dice al compilador que el contenido de una variable puede cambiarse por varios hilos. Esto evita que el compilador use optimizaciones (como leer el valor de la variable en un registro y usar ese valor en varias instrucciones) que podrían causar problemas con el acceso concurrente. Nuevamente, esto solo afecta el pequeño trozo de memoria donde se almacena la referencia.

Aplicado de esta manera, puede ver que son realmente mutuamente excluyentes. Si algo es de solo lectura (solo se puede escribir una vez, en la inicialización o construcción), entonces tampoco puede ser volátil (se puede escribir en cualquier momento mediante varios subprocesos).


En cuanto a su preocupación por los problemas de almacenamiento en caché, IIRC, hay reglas muy estrictas sobre cuando el compilador puede almacenar en caché el resultado de una llamada propiedad. Tenga en cuenta que es una llamada a método, y es una optimización bastante pesada (desde el punto de vista del compilador) almacenar en caché su valor y omitir llamar de nuevo. No creo que sea algo de lo que deba preocuparse demasiado.

+1

Las propiedades pueden ser descartables (no lo sé), pero definitivamente los campos de respaldo sí lo son. Los campos deben marcarse como volátiles. – configurator

+0

Esta respuesta responde correctamente a la pregunta del OP, pero contiene una declaración engañosa: "La palabra clave volátil le dice al compilador que el contenido de una variable podría cambiarse por varios subprocesos". Eso es solo parcialmente correcto; la palabra clave volátil también le dice al compilador que el contenido de una variable puede ser cambiado * o leído * por varios subprocesos al mismo tiempo, incluso si el cambio solo se realiza una vez. He planteado una pregunta similar aquí que cubre este problema: [falla del lenguaje C#: volátil y de solo lectura] no debe ser mutuamente exclusivo] (http://stackoverflow.com/q/39004125/1149773). – Douglas

+0

No creo que mi declaración sea engañosa. Tal vez hubiera sido más preciso decir que le dice al compilador que el valor de una variable puede ser cambiado por otros hilos mientras un hilo lo está leyendo, pero creo que * ese * fraseo es más engañoso sin más explicación, ya que podría implicar que 'volátil' es todo lo que se necesita para proporcionar sincronización de subprocesos. Creo que mi redacción explica el concepto claramente, y la siguiente oración proporciona suficientes detalles para una comprensión básica. Su problema es un examen interesante del comportamiento de inicialización de .NET, pero eso no quita nada. –

1

Un campo de solo lectura solo se puede escribir cuando el objeto se construye por primera vez. Por lo tanto, no habrá ningún problema de almacenamiento en caché en la CPU porque el campo es inmutable y no puede cambiar.

+0

Entiendo tu lógica, pero no estoy de acuerdo. Un objeto puede ser de solo lectura y aún cambia a través de sus propiedades, porque sus propiedades no son de solo lectura. La propiedad de solo lectura en este caso solo evita la asignación de la variable a otro objeto. Al menos eso es lo que entendí por lo que aprendí. –

+2

@Vernict: los modificadores de solo lectura y volátiles solo protegen la referencia (o el valor en el caso de valores atómicos como bool, int), ¡no el contenido del objeto! Esa es una cuestión completamente diferente. –

0

Aunque la referencia en sí misma podría ser segura para subprocesos, sus propiedades podrían no ser así. Piense en lo que sucedería si dos subprocesos intentaran iterar simultáneamente a través de una lista que contiene dentro de su objeto de referencia.

+0

Pero eso es algo que ni de solo lectura ni volátil pretenden proteger. Eso es algo que debes resolver de todos modos con la sincronización. –

+0

@Charlie, ¿está diciendo que incluso si el objeto es volátil, no garantiza que sus propiedades sean volátiles? –

+0

@Martin C, muy cierto. @Vernicht, según tengo entendido, sí. Deberá garantizar que sus campos y propiedades sean seguros para subprocesos. –

Cuestiones relacionadas