¿Acceder a una variable en C# es una operación atómica?

¿Acceder a una variable en C# es una operación atómica?

Para la respuesta definitiva, vaya a la especificación. :)

La sección 12.6.6 de la partición I de las especificaciones de la CLI establece:"Una CLI conforme debe garantizar que el acceso de lectura y escritura a ubicaciones de memoria correctamente alineadas que no sean más grandes que el tamaño de la palabra nativa sea atómico cuando todos los accesos de escritura a una ubicación sean del mismo tamaño ."

Eso confirma que s_Initialized nunca será inestable, y que las lecturas y escrituras en tipos primitivos de menos de 32 bits son atómicas.

En particular, double y long (Int64 y UInt64 ) no Garantizado para ser atómico en una plataforma de 32 bits. Puedes usar los métodos en el Interlocked clase para protegerlos.

Además, mientras que las lecturas y las escrituras son atómicas, existe una condición de carrera con tipos primitivos de suma, resta e incremento y decremento, ya que deben leerse, operarse y reescribirse. La clase entrelazada le permite protegerlos usando el CompareExchange y Increment métodos.

El interbloqueo crea una barrera de memoria para evitar que el procesador reordene las lecturas y escrituras. El candado crea la única barrera necesaria en este ejemplo.


Esta es una forma (mala) del patrón de bloqueo de doble verificación que no subproceso seguro en C#!

Hay un gran problema en este código:

s_Initialized no es volátil. Eso significa que las escrituras en el código de inicialización pueden moverse después de que s_Initialized se establece en verdadero y otros subprocesos pueden ver el código no inicializado incluso si s_Initialized es verdadero para ellos. Esto no se aplica a la implementación del Marco de Microsoft porque cada escritura es una escritura volátil.

Pero también en la implementación de Microsoft, las lecturas de los datos no inicializados se pueden reordenar (es decir, la CPU los obtiene previamente), por lo que si s_Initialized es verdadero, la lectura de los datos que deben inicializarse puede resultar en la lectura de datos antiguos no inicializados debido a aciertos de caché (es decir, . las lecturas se reordenan).

Por ejemplo:

Thread 1 reads s_Provider (which is null)  
Thread 2 initializes the data  
Thread 2 sets s\_Initialized to true  
Thread 1 reads s\_Initialized (which is true now)  
Thread 1 uses the previously read Provider and gets a NullReferenceException

Mover la lectura de s_Provider antes de la lectura de s_Initialized es perfectamente legal porque no hay lectura volátil en ninguna parte.

Si s_Initialized fuera volátil, no se permitiría que la lectura de s_Provider se moviera antes de la lectura de s_Initialized y tampoco se permitiría que la inicialización del proveedor se moviera después de que s_Initialized se establezca en verdadero y todo esté bien ahora.

Joe Duffy también escribió un artículo sobre este problema:Variantes rotas en el bloqueo verificado dos veces


Espera:la pregunta que está en el título definitivamente no es la verdadera pregunta que está haciendo Rory.

La pregunta principal tiene la respuesta simple de "No", pero esto no ayuda en absoluto, cuando ves la pregunta real, a la que no creo que nadie haya dado una respuesta simple.

La verdadera pregunta que hace Rory se presenta mucho más tarde y es más pertinente al ejemplo que da.

La respuesta a esto también es simple, aunque completamente ajena a la atomicidad del acceso variable.

El campo s_Initialized se lee fuera del candado porque los candados son caros .

Dado que el campo s_Initialized es esencialmente "escribir una vez", nunca devolverá un falso positivo.

Es económico leerlo fuera de la cerradura.

Este es un bajo costo actividad con un alto posibilidad de tener un beneficio.

Es por eso que se lee fuera del candado, para evitar pagar el costo de usar un candado a menos que se indique.

Si las cerraduras fueran baratas, el código sería más simple y omitiría esa primera comprobación.

(editar:sigue una buena respuesta de rory. Sí, las lecturas booleanas son muy atómicas. Si alguien construyera un procesador con lecturas booleanas no atómicas, aparecerían en el DailyWTF).