Pregunta

En otras palabras, ¿puedo hacer algo con una variable volátil que no podría resolverse con una variable normal y la clase entrelazada?

¿Fue útil?

Solución

Editar: Pregunta en gran medida reescritada

Para responder a esta pregunta, me sumergí un poco más en el asunto y descubrí algunas cosas sobre volatile y Interlocked que no estaba al tanto. Claro eso, no solo para mí, sino para esta discusión y otras personas que leen sobre esto:

  • volatile Se supone que la lectura/escritura es inmune al reordenamiento. Este solamente significa leer y escribir, lo hace no significa cualquier otra acción;
  • volatilidad no se ve forzado en el nivel de hardware de CPU, es decir, (x86 utiliza cercas de adquisición y lanzamiento en ningún leer escribir). Prevenida las optimizaciones del compilador o CLR;
  • Interlocked utiliza instrucciones de ensamblaje atómico para comparación (cmpxchg), Incremento (inc) etc;
  • Interlocked se usa A veces un bloqueo: un Bloqueo de hardware en sistemas de procesadores múltiples; En los sistemas uni-procesador, no hay bloqueo de hardware;
  • Interlocked es diferente de volatile en que usa un valla, donde volátil usa una media cerca.
  • Se puede reordenar una lectura después de una escritura Cuando usas volatile. No puede pasar con Interlocked. VolatileRead y VolatileWrite Tenga el mismo problema de reordenamiento que `Volátil (enlace gracias a Brian Gideon).

Ahora que tenemos las reglas, podemos definir una respuesta a su pregunta:

  • Técnicamente: sí, hay cosas que puedes hacer con volatile que no puedes hacer con Interlocked:
    1. Sintaxis: no puedes escribir a = b dónde a o b es volátil, pero esto es obvio;
    2. Puede leer un valor diferente después de escribirlo en una variable volátil debido al reordenamiento. No puedes hacer esto con Interlocked. En otras palabras: puedes ser menos a salvo con volatile Entonces puedes estar con Interlocked.
    3. Actuación: volatile es más rápido entonces Interlocked.
  • Semánticamente: no, porque Interlocked Simplemente proporciona un superconjunto de operaciones y es más seguro de usar porque aplica una cerca completa. No puedes hacer nada con volatile que no puedes hacer con Interlocked Y puedes hacer mucho con Interlocked que no puedes hacer con volátil:

    static volatile int x = 0;
    x++;                        // non-atomic
    static int y = 0;
    Interlocked.Increment(y);   // atomic
    
  • Alcance: Sí, declarando una variable volatile lo hace volátil para cada acceso. Es imposible forzar este comportamiento de otra manera, por lo tanto volatile no se puede reemplazar con Interlocked. Esto se necesita en escenarios en los que otras bibliotecas, interfaces o hardware pueden acceder a su variable y actualizarla en cualquier momento, o necesitan la versión más reciente.

Si me preguntas, este último bit es la verdadera necesidad real de volatile y puede hacerlo ideal donde dos procesos comparten memoria y necesitan leer o escribir sin bloquear. Declarando una variable como volatile es mucho más seguro en este contexto y luego obligar a todos los programadores a usar Interlocked (que no puede forzar por el compilador).


Editar: la siguiente cita fue parte de mi respuesta original, la dejaré en ;-)

Una cita del Lenguaje de programación C# estándar:

Para los campos no volátiles, las técnicas de optimización que consideran que las instrucciones de reorden pueden conducir a resultados inesperados e impredecibles en programas múltiples que acceden a los campos sin sincronización, como las proporcionadas por el establecimiento de bloqueo. Estas optimizaciones pueden realizar el compilador, por el sistema de tiempo de ejecución o por hardware. Para campos volátiles, tales optimizaciones de reordenamiento están restringidas:

  • Una lectura de un campo volátil se llama lectura volátil. Una lectura volátil tiene: adquirir semántica "; es decir, se garantiza que ocurra antes de cualquier referencia a la memoria que ocurra después de la secuencia de instrucciones.

  • Una escritura de un campo volátil se llama escritura volátil. Una escritura volátil tiene "semántica de lanzamiento"; Es decir, se garantiza que ocurrirá después de cualquier referencia de memoria antes de la instrucción de escritura en la secuencia de instrucciones.

Actualizar: Pregunta en gran medida reescritada, corrigió mi respuesta original y agregó una respuesta "real"

Otros consejos

Este es un tema bastante complejo. Encuentro el Joseph Albahari's redacción Ser una de las fuentes más definitivas y precisas para los conceptos de lectura múltiple en el marco de .NET que podrían ayudar a responder a su pregunta.

Pero, para resumir rápidamente, hay mucha superposición entre el volatile palabra clave y el Interlocked clase en cuanto a cómo se pueden usar. Y, por supuesto, ambos van mucho más allá de lo que puede hacer con una variable normal.

Sí, puedes mirar el valor directamente.

Siempre que solo use la clase entrelazada para acceder a la variable, entonces no hay diferencia. Qué volátil Do es que le dice al compilador que la variable es especial y al optimizarla no debe asumir que el valor no ha cambiado.

Toma este bucle:

bool done = false;

...

while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}

Si te configuras done a true En otro hilo, esperarías que salga el bucle. Sin embargo, si se hace no está marcado como volatile Entonces el compilador tiene la opción de darse cuenta de que el código de bucle nunca puede cambiar done y puede optimizar la comparación de la salida.

Esta es una de las cosas difíciles de la programación multiproceso: muchas de las situaciones que son problemas solo surgen en ciertas situaciones.

No intentaré ser una autoridad en este tema, pero le recomiendo que eche un vistazo a Este artículo por el jon Skeet.

También eche un vistazo a la parte final de esta respuesta que detalla que volatile debe usarse para.

Sí, puede obtener algo de rendimiento utilizando una variable volátil en lugar de un bloqueo.

Lock es una barrera de memoria completa que puede darle las mismas características de una variable volátil, así como muchas otras. Como ya se ha dicho, volátiles solo asegura que en escenarios multiprocesos si una CPU cambia un valor en su línea de caché, las otras CPU ve el valor de inmediato, pero no garantiza ninguna semántica de bloqueo en absoluto.

La cosa es que el bloqueo es mucho más potente que volátil y debe usar volátiles cuando pueda para evitar cerraduras innecesarias.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top