2010-03-19 12 views
5

He estado leyendo la respuesta a una similar question, pero todavía estoy un poco confundido ... Abel tuvo una gran respuesta, pero esta es la parte que estoy seguro acerca de:¿El enclavamiento garantiza la visibilidad de otros hilos en C# o aún tengo que usar volátiles?

.. .declarar una variable volátil lo hace volátil para cada acceso . Es imposible forzar este comportamiento de de otra manera, por lo tanto, el volátil no se puede reemplazar con Enclavamiento. Esto es necesario en escenarios donde otras bibliotecas, interfaces o hardware pueden acceder a su variable y actualizarla en cualquier momento, o necesitan la versión más reciente .

¿Tiene Interlocked visibilidad garantía de la operación atómica de todas las discusiones, o tengo todavía tiene que utilizar la palabra clave volatile en el valor con el fin de garantizar la visibilidad del cambio?

Aquí está mi ejemplo:

volatile int value = 100000; // <-- do I need the volitile keyword 
// .... 

public void AnotherThreadMethod() 
{ 
while(Interlocked.Decrement(ref value)>0) 
{ 
    // do something 
} 
} 


public void AThreadMethod() 
{ 
while(value > 0) 
{ 
    // do something 
} 
} 

Actualización:
yo era un mal deportista y he cambiado el ejemplo original, por lo que aquí está otra vez:

public class CountDownLatch 
{ 
    private volatile int m_remain; // <--- do I need the volatile keyword here? 
    private EventWaitHandle m_event; 

    public CountDownLatch(int count) 
    { 
     Reset(count); 
    } 

    public void Reset(int count) 
    { 
     if (count < 0) 
      throw new ArgumentOutOfRangeException(); 
     m_remain = count; 
     m_event = new ManualResetEvent(false); 
     if (m_remain == 0) 
     { 
      m_event.Set(); 
     } 
    } 

    public void Signal() 
    { 
     // The last thread to signal also sets the event. 
     if (Interlocked.Decrement(ref m_remain) == 0) 
      m_event.Set(); 
    } 

    public void Wait() 
    { 
     m_event.WaitOne(); 
    } 
} 
+0

Lo siento por las ediciones múltiples ... Remus ha sido un buen deportista al respecto. ¡Gracias por la información! :) – Kiril

Respuesta

5

ellos no lo hacen * necesita ** volatilidad, porque nunca verifica el valor de la variable entrelazada. En su lugar, siempre verifica el valor devuelto por la (s) operación (es) interbloqueada (s). La mezcla de operaciones entrelazadas y la asignación/comparación ordinaria siempre da como resultado un código incorrecto.

No estoy seguro de cuál es la intención de la función Reset(), pero ese fragmento de código no tiene cabida en la primitiva entre hilos: asignar a m_remain, comprobar el valor de m_remain directamente, es bastante malo. Le sugiero encarecidamente que lo saque: no solo se implementa incorrectamente, sino que dudo mucho de que se necesite la semántica de "reiniciar" el contador a mitad de la vida útil. Déjalo simple: ctor (mueve el código de Restablecer a él) Signal and Wait son los únicos tres operadores necesarios, y son correctos como lo son ahora.

Actualizado Después de haber editado el código.

Ignorando el hecho de que no debe mezclar los dos, si termina mezclándolos, entonces sí, todavía es necesario volátil. Volatile se trata principalmente del código IL y el código JIT generado para garantizar que el valor siempre se lea desde la ubicación real de la memoria y no se produzca ninguna optimización, como la reordenación del código. El hecho de que una pieza de código no relacionada actualice el valor utilizando operaciones Interbloqueadas no tiene efecto en otras partes que leen el valor. Sin un atributo volatile, el compilador/JIT aún puede generar código que ignora las escrituras que ocurren en otro lugar, irrelevante si las escrituras están entrelazadas o asignadas directamente.

Por cierto, existen patrones válidos que combinan las operaciones de lectura y enclavamiento comunes, pero por lo general implican Interlocked.CompareExchange y el siguiente: leer el estado actual, hacer un cálculo basado en el estado actual, intentar reemplazar el estado como un enclavamiento compare-exchange: si tiene éxito, si no, suelte el resultado del cálculo y vuelva al paso 1.

+0

Bueno, mi publicación tiene sentido antes de editar su lol –

+0

Lo siento, puse el ejemplo de copia de seguridad ... ¡Realmente no quise engañarte! :) – Kiril

+0

Así sale la función Restablecer ... realmente no tiene ningún sentido. Pensé que podría ser útil para reutilizar el mismo pestillo, pero agrega más confusión que cualquier otra cosa. – Kiril

1

Creo que System.Threading.Thread.VolatileRead (ref myVariable) podría ser lo que está buscando.Usado junto con Interlocked.Increment se puede usar para garantizar que los cambios sean atómicos y que los valores que lea sean los más recientes.

Cuestiones relacionadas