Podría estar saltando la pistola aquí, pero me parece que está confundiendo dos cuestiones aquí.
Uno es la atomicidad, que en mi mente significa que una sola operación (que puede requerir varios pasos) no debe entrar en conflicto con otra operación única.
La otra es la volatilidad, cuando se espera que cambie este valor, y por qué.
Tome la primera. Si su operación en dos pasos requiere que lea el valor actual, lo modifique y lo vuelva a escribir, seguramente querrá un bloqueo, a menos que toda esta operación se pueda traducir en una sola instrucción de CPU que pueda funcionar en un única línea de caché de datos.
Sin embargo, el segundo problema es que, incluso cuando se está bloqueando, lo que verán otros subprocesos.
Un campo volatile
en .NET es un campo que el compilador sabe que puede cambiar en momentos arbitrarios. En un mundo de subproceso único, el cambio de una variable es algo que sucede en algún punto de una secuencia de instrucciones secuencial, de modo que el compilador sabe cuándo ha agregado el código que lo cambia, o al menos cuando ha llamado al mundo exterior que puede o no haberlo cambiado para que, una vez que el código regrese, no tenga el mismo valor que tenía antes de la llamada.
Este conocimiento permite al compilador levantar el valor del campo en un registro una vez, antes de un bucle o bloque de código similar, y nunca volver a leer el valor del campo para ese código en particular.
Sin embargo, con multi-threading, eso podría ocasionarle algunos problemas. Un hilo puede haber ajustado el valor, y otro hilo, debido a la optimización, no leerá este valor durante un tiempo, porque sabe que no ha cambiado.
Por lo tanto, cuando marca un campo como volatile
, básicamente le está diciendo al compilador que no debe suponer que tiene el valor actual de esto en ningún momento, excepto para capturar instantáneas cada vez que necesita el valor.
Las cerraduras resuelven operaciones de varios pasos, la volatilidad maneja cómo el compilador guarda en caché el valor del campo en un registro, y juntos resolverán más problemas.
También tenga en cuenta que si un campo contiene algo que no se puede leer en una sola instrucción de CPU, lo más probable es que también desee bloquear el acceso de lectura a él.
Por ejemplo, si está en una CPU de 32 bits y escribe un valor de 64 bits, esa operación de escritura requerirá dos pasos para completarse, y si otra cadena en otra CPU logra leer el 64-bit antes de que se complete el paso 2, obtendrá la mitad del valor anterior y la mitad del nuevo, muy bien mezclado, lo que puede ser incluso peor que obtener uno obsoleto.
Editar: Para contestar el comentario, que volatile
garantiza la atomicidad de la operación de lectura/escritura, eso es así, es cierto, en cierto modo, por la palabra clave volatile
no se puede aplicar a los campos que son mayores que De 32 bits, en efecto, hace que el campo single-cpu-instruction sea legible/escribible tanto en la CPU de 32 como en la de 64 bits.Y sí, evitará que el valor se mantenga en un registro tanto como sea posible.
De modo que parte del comentario es incorrecto, volatile
no se puede aplicar a los valores de 64 bits.
Tenga en cuenta también que volatile
tiene alguna semántica con respecto a la reordenación de lecturas/escrituras. Para obtener información relevante, consulte MSDN documentation o C# specification, encontrado here, sección 10.5.3.
Es * una lectura bastante buena (y definitivamente merece un +1), pero normalmente se prefiere que las respuestas SO sean un tanto independientes. Sería bueno que su respuesta contuviera un resumen de las partes importantes de ese artículo, solo para que (1) las personas que roban la página lo vean y (2) para que la respuesta permanezca relevante si el artículo se mueve o se quita. – jalf