¿Es atómico acceder a un campo bool en C #? En particular, necesito poner un candado alrededor:
class Foo
{
private bool _bar;
//... in some function on any thread (or many threads)
_bar = true;
//... same for a read
if (_bar) { ... }
}
Respuestas:
Si.
como se encuentra en C # Language Spec .
Editar: Probablemente también valga la pena comprender la palabra clave volátil .
fuente
Interlocked.Add(ref myInt);
por ejemplo?i++
es igual ai=i+1
, lo que significa que haces una lectura atómica, luego una suma y luego una escritura atómica. Otro hilo podría modificarsei
después de la lectura pero antes de la escritura. Por ejemplo, dos subprocesos que funcionani++
simultáneamente en el mismo i pueden leer al mismo tiempo (y, por lo tanto, leer el mismo valor), agregar uno y luego ambos escriben el mismo valor, agregando efectivamente solo una vez. Interlocked.Add evita esto. Como regla general, el hecho de que un tipo sea atómico solo es útil si solo hay un hilo escribiendo pero muchos hilos leyendo.Como se indicó anteriormente, bool es atómico, pero aún debe recordar que también depende de lo que quiera hacer con él.
if(b == false) { //do something }
no es una operación atómica, lo que significa que el valor de b podría cambiar antes de que el hilo actual ejecute el código después de la instrucción if.
fuente
Los accesos bool son de hecho atómicos, pero esa no es toda la historia.
No tiene que preocuparse por leer un valor que está 'escrito de forma incompleta' (no está claro qué podría significar eso para un bool en cualquier caso), pero debe preocuparse por las cachés del procesador, al menos si hay detalles de el tiempo es un problema. Si el hilo n. ° 1 que se ejecuta en el núcleo A tiene su
_bar
caché y_bar
se actualiza mediante el hilo n. ° 2 que se ejecuta en otro núcleo, el hilo n. ° 1 no verá el cambio inmediatamente a menos que agregue bloqueo, declare_bar
comovolatile
o inserte explícitamente llamadas aThread.MemoryBarrier()
para invalidar el valor en caché.fuente
var fatObject = new FatObject(); Thread.MemoryBarrier(); _sharedRefToFat = fatObject;
el enfoque que he utilizado, y creo que es correcto, es
volatile bool b = false; .. rarely signal an update with a large state change... lock b_lock { b = true; //other; } ... another thread ... if(b) { lock b_lock { if(b) { //other stuff b = false; } } }
el objetivo era básicamente evitar tener que bloquear repetidamente un objeto en cada iteración solo para verificar si necesitábamos bloquearlo para proporcionar una gran cantidad de información de cambio de estado que ocurre raramente. Creo que este enfoque funciona. Y si se requiere una consistencia absoluta, creo que lo volátil sería apropiado en el b bool.
fuente
lock()
, no es necesariovolatile
.