2009-11-09 18 views

Respuesta

15

EDIT: pregunta reescrito en gran medida

Para responder a esta pregunta, he buceado un poco más en el asunto y descubrí algunas cosas sobre volatile y Interlocked que yo no era consciente. Vamos a aclarar eso, no sólo para mí, pero para esta discusión y otras personas que lean sobre esto:

  • volatile de lectura/escritura se supone que son inmunes a la reordenación. Esto solo significa leer y escribir, hace no significa cualquier otra acción;
  • la volatilidad no es forzado en la CPU, es decir, a nivel de hardware (x86 utiliza adquirir y liberar vallas en cualquier de lectura/escritura). Previene optimizaciones de compilador o CLR;
  • Interlocked usa instrucciones de ensamblaje atómicas para CompareExchange (cmpxchg), Incremento (inc) etc;
  • Interlockedusa veces un candado: a hardware lock on multi processor systems; en los sistemas de procesador único, no hay bloqueo de hardware;
  • Interlocked es diferente de volatile en que utiliza una valla completa, donde volatil utiliza una media valla.
  • A read following a write can be reordered cuando usa volatile. No puede suceder con Interlocked. VolatileRead y VolatileWrite tienen el mismo problema de reordenación 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 puede hacer con volatile que no se puede hacer con Interlocked:
    1. sintaxis: no se puede escribir a = b donde a o b es volátil, pero esto es obvia;
    2. se puede leer un valor diferente después de escribir a una variable volátil debido a la reordenación. No puede hacer esto con Interlocked. En otras palabras: puede ser menos seguro con volatile, entonces puedes estar con Interlocked.
    3. Rendimiento: volatile es más rápido que Interlocked.
  • vista semántico: no, porque Interlocked simplemente proporciona un superconjunto de las operaciones y es más seguro de usar, ya que se aplica la esgrima completo. No se puede hacer nada con volatile que no se puede ver con Interlocked y se puede hacer mucho con Interlocked que no se puede ver con volátil:

    static volatile int x = 0; 
    x++;      // non-atomic 
    static int y = 0; 
    Interlocked.Increment(y); // atomic 
    
  • Alcance: sí, se declara una variable volatile hace que sea volátil para cada acceso individual. Es imposible forzar este comportamiento de otra manera, por lo tanto, volatile no se puede reemplazar por Interlocked. Esto es necesario en escenarios donde 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 preguntan, este último es la verdadera necesidad real para volatile y puede hacer que sea ideal donde los dos procesos comparten memoria y necesitan leer o escribir sin bloquear. La declaración de una variable como volatile es mucho más seguro en este contexto, a continuación, obligando a todos los programadores utilizar Interlocked (que no se puede forzar por el compilador).


EDIT: La siguiente cita fue parte de mi respuesta original, lo dejaré en ;-)

Una cita de la el C# lenguaje de programación estándar:

Para campos no volátiles, optimización técnicas que consideran que las instrucciones de reorden pueden dar como resultado inesperados y resultados impredecibles i n programas multiproceso que acceden a los campos sin sincronización, como que proporciona instrucción de bloqueo. Estos optimizationscan ser realizadas por el compilador, el sistema de ejecución, o por el hardware.Para los campos de volátiles, tales optimizaciones de reordenamiento son restringido:

  • Una lectura de un campo volátil se llama un volátil leer. Un volátil leer ha:. Adquirir semántica ", es decir, que se garantiza que se produzca antes de cualquier referencias a la memoria que se producen después en la secuencia de instrucciones

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

Actualización: pregunta reescrito en gran medida, corregida mi respuesta original y añade un "verdadero" respuesta

+0

La clase Interbloqueada no tiene que hacer mucho con un bloqueo y tiene (a diferencia de la cerradura) no mucha sobrecarga asignada con él - en la mayoría de las CPU los métodos Enclavados se implementan como una sola instrucción. – codymanix

+0

Tiene razón, gracias por señalarlo. Al examinar 'CompareExchange' (pensando que no sería atómico), SSCLI (CLI de fuente compartida) muestra que finalmente se traduce en la instrucción de ensamblaje' cmpxchg' en procesadores x86, y que la instrucción es, como cualquier otra cosa en 'Interlocked', de hecho atómico. – Abel

+0

Que, y otras correcciones, además de reescribir están ahora en la respuesta :) – Abel

0

Sí, puede ver el valor directamente.

Mientras SÓLO uses la clase Interbloqueada para acceder a la variable, entonces no hay diferencia. Lo que volátil hace es 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 establece done a true en otro hilo que se puede esperar del bucle para salir. Sin embargo, si está hecho no está marcado como volatile, entonces el compilador tiene la opción de darse cuenta de que el código del bucle nunca puede cambiar done y puede optimizar la comparación para 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.

+0

Puede hacer lo mismo con Interlocked.Read(). – codymanix

+1

Tu descripción de volátil es levemente incorrecta. Usted describe C++ volátil (no es bueno para multihilo). C# (y Java) volátil hacen que el compilador inserte las operaciones de sincronización cuando accede a la variable. Debido a las sincronizaciones, se ve obligado a volver a leer la variable cada vez, lo que tiene un efecto similar al volátil de C++. –

1

Este es un tema bastante complejo. Encuentro el writeup de Joseph Albahari como una de las fuentes más definitivas y precisas para conceptos de subprocesamiento múltiple en .NET Framework que podría ayudar a responder su pregunta.

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

+0

¡Artículo muy bueno! Tomará un tiempo leerlo y mucho más tiempo para comprenderlo por completo – codymanix

0

No intentaré ser una autoridad en este tema, pero le recomendaría que echara un vistazo al this article del famoso Jon Skeet.

También eche un vistazo a la parte final de this answer que detalla para qué se debe usar volatile.

+0

El artículo de Skeet es bueno, pero solo abarca los conceptos básicos. Sé para qué sirve la volatilidad, pero la pregunta era si hay alguna situación en la que no puedas reemplazar la volatilidad con un método interconectado. – codymanix

-1

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

La cerradura es una barrera de memoria completa que puede darle las mismas características de una variable volátil y muchas otras. Como ya se ha dicho, volátil solo asegura que en escenarios de subprocesos múltiples si una CPU cambia un valor en su línea de caché, las otras CPU ven el valor inmediatamente pero no aseguran ninguna semántica de bloqueo en absoluto.

Lo que pasa es que el bloqueo es mucho más potente que el volátil y debes usar volátiles cuando puedas para evitar bloqueos innecesarios.

+0

No estaba hablando de la declaración de bloqueo, sino de la clase Interbloqueada, pero sí lo que dijiste es cierto – codymanix

Cuestiones relacionadas