2010-01-20 19 views
10

Sé que el modelo de memoria .NET (en .NET Framework; no compacto/micro/silverlight/mono/xna/what-have-you) garantiza que para ciertos tipos (más notablemente primitivos enteros y referencias) se garantizaron las operaciones ser atómico. Modelo de memoria .NET, variables volátiles y prueba y conjunto: ¿qué se garantiza?

Además, creo que las instrucciones de prueba y configuración x86/x64 (y Interlocked.CompareExchange) hacen referencia en realidad a la ubicación de memoria global, por lo que si tiene éxito, otra Interlocked.CompareExchange vería el nuevo valor.

Por último, creo que la palabra clave volatile es una instrucción para el compilador para propagar lee & escribe lo antes posible y para no cambiar el orden de las operaciones relativas a esta variable (¿verdad?).

Esto conduce a una serie de preguntas:

  1. Son mis creencias anteriores correcta?
  2. Interlocked.Read no tiene una sobrecarga para int, solo para long (que son 2 WORD y por lo tanto normalmente no se leen atómicamente). Siempre asumí que el modelo de memoria .NET garantizaba que se vería el valor más nuevo al leer ints/references, sin embargo con cachés de procesador, registros, etc. Estoy empezando a ver que esto puede no ser posible. Entonces, ¿hay alguna manera de obligar a la variable a ser recuperada?
  3. ¿Es volátil suficiente para resolver el problema anterior para enteros y referencias?
  4. en x86/x64 puedo suponer que ...

Si hay dos variables globales enteros x e y, a la vez inicializado a 0 que si escribo:

x = 1; 
y = 2; 

que ningún hilo verá x = 0 y y = 2 (es decir, las escrituras se realizarán en orden). ¿Esto cambia si son volátiles?

Respuesta

6
  • Solo lee y escribe en variables que tienen a lo sumo 32 bits de ancho (y 64 bits de ancho en sistemas x64) son atómicas. Todo esto significa que no leerá int y obtendrá un valor medio escrito. No significa que la aritmética sea atómica.
  • Las operaciones interbloqueadas también actúan como barreras de memoria, así que sí, Interlocked.CompareExchange verá el valor actualizado.
  • Ver this page. Volátil no significa ordenado. Algunos compiladores pueden optar por no reordenar operaciones en variables volátiles, pero la CPU es libre de reordenar. Si desea evitar que la CPU vuelva a ordenar las instrucciones, use una barrera de memoria (completa).
  • El modelo de memoria garantiza que las lecturas y escrituras sean atómicas, y el uso de la palabra clave volátil garantiza que las lecturas serán siempre provienen de la memoria, no de un registro. Entonces, será, verá el valor más nuevo. Esto se debe a que las CPU x86 anularán la caché cuando corresponda; consulte this y this. Además, consulte InterlockedCompareExchange64 para saber cómo leer atómicamente los valores de 64 bits.
  • Y finalmente, la última pregunta.La respuesta es que un hilo podría, de hecho, ver x = 0 y y = 2, y usar la palabra clave volátil no cambia eso porque la CPU puede reordenar las instrucciones. Necesitas una barrera de memoria.

Resumen:

  1. El compilador es libre de volver a pedir instrucciones.
  2. La CPU puede reordenar las instrucciones.
  3. Las lecturas y escrituras del tamaño de la palabra son atómicas. La aritmética y otras operaciones no son atómicas porque implican leer, computar y luego escribir.
  4. Las lecturas de tamaño de Word de la memoria siempre recuperarán el valor más reciente. Pero la mayoría de las veces no sabes si estás leyendo de memoria.
  5. Una barrera de memoria completa se detiene (1) y (2). La mayoría de los compiladores le permiten detenerse (1) por sí mismo.
  6. La palabra clave volátil garantiza que está leyendo desde la memoria - (4).
  7. Las operaciones entrelazadas (el prefijo de bloqueo) permiten que múltiples operaciones sean atómicas. Por ejemplo, una lectura + escritura (InterlockedExchange). O una lectura + comparar + escribir (InterlockedCompareExchange). También actúan como barreras de memoria, por lo que (1) y (2) se detienen. Siempre escriben en la memoria (obviamente), así que (4) está garantizado.
+2

El problema con vincular a "C Keyword Mths Dispelled" en algo sobre .NET es que una fuente importante de mitos sobre 'volátil' es que las personas actúan como si fuera lo mismo en C, C# y Java. En C# 'volátil' de hecho tiene un poco de semántica ordenando según http://msdn.microsoft.com/en-us/library/aa645755%28v=VS.71%29.aspx. –

+0

"el hilo de hecho podría ver x = 0 y y = 2" - ya que las operaciones de escritura de .NET 2.0 no se pueden reordenar. – Vlad

0

No, la palabra clave volátil y la garantía de atomicidad son demasiado débiles. Necesitas una barrera de memoria para asegurarte. Puede obtener uno explícitamente con el método Thread.MemoryBarrier().

+0

Bien ... eso responde 2 y 3, pero ¿qué pasa con el n. ° 4 (orden en que hilos verán los datos)? –

+0

También desde: http://msdn.microsoft.com/en-us/library/x13ttww7%28VS.71%29.aspx (lol msdn urls): "El sistema siempre lee el valor actual de un objeto volátil en el punto se solicita, incluso si la instrucción previa solicitó un valor del mismo objeto. Además, el valor del objeto se escribe inmediatamente en la asignación. El modificador volátil generalmente se usa para un campo al que se accede mediante varios subprocesos sin usar el bloqueo declaración para serializar el acceso. Usar el modificador volátil asegura que un hilo recupere el valor más actualizado escrito por otro hilo ". –

+0

Ah, y el código de ejemplo en http://msdn.microsoft.com/en-us/library/aa645755% 28VS.71% 29.aspx - Esto parece contradecir su respuesta. –

2

Encontré este viejo hilo. Las respuestas de Hans y wj32 son todas correctas excepto por la parte relacionada con volatile.

Específicamente con respecto a su pregunta

en x86/x64 puede supongo que ... Si hay dos variables enteras globales X e Y, tanto inicializado a 0 que si escribo: x = 1; y = 2;

Que NO thread verá x = 0 y y = 2 (es decir, las escrituras se realizarán en el orden ). ¿Esto cambia si son volátiles?

Si y es volátil, la escritura en x es garantía de que ocurra antes de la escritura a y, por lo tanto, ningún hilo verá nunca x = 0 y y = 2. Esto se debe a que la escritura en una variable volátil tiene la "semántica de liberación" (lógicamente equivalente a la emisión de una valla de liberación), es decir, todas las instrucciones de lectura/escritura antes de que no se muevan la pasen. (Esto implica que si x es volátil pero y no lo es, aún puede ver el inesperado x = 0 y y = 2). Consulte la descripción del ejemplo del código & en el C# spec para obtener más detalles.

Cuestiones relacionadas