.NETO modelo de memoria, la volatilidad de las variables, y de la prueba-y-set:lo que está garantizado?
-
21-09-2019 - |
Pregunta
Sé que el .NETO modelo de memoria (en el .NET Framework;no compacto/micro/silverlight/mono/xna/lo-que-usted) garantiza que para ciertos tipos (más notablemente primitivo enteros y referencias) operaciones están garantizados para ser atómica.
Además, creo que el x86/x64 test-and-set de instrucciones (y Interlocked.CompareExchange
) en realidad hace referencia a la memoria global de la ubicación, así que si sucede a otro Interlocked.CompareExchange
iba a ver el nuevo valor.
Por último, creo que la volatile
palabra clave es una instrucción para el compilador para propagar lee y graba lo antes posible para no reordenar las operaciones relativas a esta variable (a la derecha?).
Esto lleva a un par de preguntas:
- Son mis creencias sobre la correcta?
Interlocked.Read
no tiene una sobrecarga para int, sólo para anhela (que son 2 Palabras y por lo tanto no se suelen leer de forma atómica).Siempre he asumido que la .NETO modelo de memoria garantiza que el valor más reciente sería visto al leer enteros/referencias, sin embargo con el procesador almacena en caché, registros, etc.Estoy empezando a ver esto no puede ser posible.Entonces, ¿hay una manera de forzar la variable a ser re-fetched?- Es volátil suficiente para resolver el problema anterior para los números enteros y las referencias?
- En los sistemas x86/x64 puedo asumir que...
Si hay dos entero global de las variables x e y, ambos se inicializa a 0, que si yo escribo:
x = 1;
y = 2;
Que NO el hilo se ve que x = 0 y y = 2 (es decir,las escrituras se producirá en orden).¿Este cambio si son volátiles?
Solución
- Sólo lee y escribe en variables que son como máximo 32 bits de ancho (y 64 bits de ancho x 64 de los sistemas) son atómicas. Todos significa esto es que no vas a leer un int y obtener un valor medio escribir. No lo hace media aritmética es atómica.
- Las operaciones de interbloqueo también actúan como barreras de memoria, así que sí,
Interlocked.CompareExchange
verá el valor actualizado. - esta página . Volátil no significa que sean ordenados. Algunos compiladores pueden optar por no volver a pedir las operaciones sobre las variables volátiles, pero la CPU es libre de volver a pedir. Si desea detener la CPU de instrucciones de re-ordenamiento, utilizar una (completa) barrera de memoria.
- el modelo de memoria asegura que lee y escribe son atómicas, y utilizando las palabras clave asegura volátiles que se lee siempre provienen de la memoria, no a partir de un registro. Por lo que ver el valor más reciente. Esto se debe a que las CPU x86 invalidará la caché cuando sea apropiado - véase este y esta . Asimismo, consulte InterlockedCompareExchange64 de cómo atómicamente leer valores de 64 bits.
- Y finalmente, la última pregunta. La respuesta es un hilo de hecho, podría ver
x = 0
yy = 2
, y el uso de la palabra clave volátil que no cambia porque la CPU está libre para volver a pedir instrucciones. Se necesita una barrera de memoria.
Resumen:
- El compilador es libre de volver a pedir instrucciones.
- La CPU es libre de volver a pedir instrucciones.
- dimensionada-Word lecturas y escrituras son atómicos. Las operaciones aritméticas y otros no son atómicos porque implican una lectura, cálculo, a continuación, escribir.
- dimensionada-Word lee de la memoria será siempre recuperar el valor más reciente. Pero la mayoría de las veces no sé si en realidad estás leyendo la memoria.
- Detiene una barrera de memoria completo (1) y (2). La mayoría de los compiladores le permiten detener (1) por sí mismo.
- Los volátiles le asegura palabra clave está leyendo de la memoria -. (4)
- Las operaciones de interbloqueo (el prefijo de bloqueo) permite múltiples operaciones sean atómica. Por ejemplo, una lectura + escritura (InterlockedExchange). O una lectura + + comparar escritura (InterlockedCompareExchange). También actúan como barreras de memoria, por lo que (1) y (2) se detienen. Siempre escribir en la memoria (obviamente), por lo que (4) está garantizada.
Otros consejos
Llegaron a través de este hilo viejo.Las respuestas de Hans y wj32 son todas correctas, excepto por la parte en relación volatile
.
Específicamente en cuanto a tu pregunta
En los sistemas x86/x64 puedo asumir que...Si hay dos mundial de variables de tipo integer x e y, ambos se inicializa a 0, que si Yo escribo:
x = 1; y = 2;
Que NO el hilo se vea x = 0 y y = 2 (es decir,las escrituras de se producen en orden).¿Este cambio si ellos son volátiles?
Si y
es volátil, el escribir a x
se garantiza a suceder antes de que la escritura a y
, por lo tanto no el hilo va a ver x = 0
y y = 2
.Eso es porque la escritura no volátil variable tiene la "liberación de la semántica" (lógicamente equivalente a la emisión de un comunicado de cerca), es decir,todos los de lectura/escritura de instrucciones antes de que no se mueva pasar.(Esto implica que si x es volátil pero y es que no, usted todavía puede ver el inesperado x = 0
y y = 2
.) Ver la descripción y el código de ejemplo en el C# spec para obtener más detalles.
No, la palabra clave volátil y la garantía de la atomicidad son demasiado débiles. Se necesita una barrera de memoria para asegurarse de que. Usted puede obtener una forma explícita con el método Thread.MemoryBarrier ().