2012-10-04 30 views
7

Este programa ejecuta dos hilos diferentes y me dice quién es el ganador de la "carrera".Variante del algoritmo de Dekker confusión

Inesperadamente a veces AMBOS hilos "gana" (esperaba que alguien o nadie ganara). ¿Es este comportamiento esperado y por qué? Obviamente me falta algo fundamental aquí.

class Program 
{ 
    public volatile static int a = 0; 
    public volatile static int b = 0; 

    public static void Main() 
    { 
     for(int i = 0; i < 1000; i++) 
     { 
      a = 0; 
      b = 0; 

      Parallel.Invoke(delegate { a = 1; if (b == 0) Console.WriteLine("A wins"); }, 
          delegate { b = 1; if (a == 0) Console.WriteLine("B wins"); }); 

      Console.WriteLine(System.Environment.NewLine); 

      Thread.Sleep(500); 
     } 
    } 
} 

Resultados:

A wins 

B wins 

A wins 
B wins 

A wins 

... 
+0

Al cambiar la implementación de 'Parallel' a' Old Thread's, parece funcionar. (No sé por qué todavía) –

+0

@LB: Interesante, es probable que sea porque los hilos se ejecutan en el mismo procesador- ¿núcleo? –

+0

configuración 'TaskCreationOptions.LongRunning' también parece hacer que funcione correctamente. –

Respuesta

3

Estás utilizando volátil incorrectamente:

declarar las variables volátiles no es suficiente, es necesario asegurarse de que todo el mundo que lee/escribe de ellos, se utiliza Thread.VolatileRead(ref myVar)/Thread.VolatileWrite(ref myVar)

Además, volátiles does NOT aseguran el orden de lectura/escritura (de diferentes hilos), incluso si se usan correctamente. Navegue SO para obtener información sobre el tema. EDIT: it seems to do en una máquina de un solo núcleo x86

simplemente podría utilizar la instrucción lock, pero si quieres llegar al fondo de esto, yo recomiendo la lectura, la comprensión, a continuación, leer de nuevo this free e-book

ADICIONES:
Acabo de navegar a través de la clase Parallel en .NET 4, y en ninguna parte se usa la palabra clave volatile.
También copian la matriz de Action<T> antes de pasar sobre ella por alguna razón, pero dudo que eso te impacte.

+0

+1. Usando el hilo.VolatileRead (ref myVar) etc. realmente da el comportamiento esperado. Mis suposiciones son (y lo que quería ver en primer lugar) que los resultados de no declarar las variables como volátiles (sin insertar las barreras de memoria correctas) dan un buen ejemplo del modelo de memoria relajado. Si quieres profundizar en eso, siéntete libre. Probablemente marque esto como aceptado, si no se da una explicación más detallada de POR QUÉ sucede esto. ¡Gracias! –

+0

@JK. lea el e-book gratuito para obtener una explicación * detallada * (¡pero prepárese!). –

+0

Leí el libro electrónico. Según tengo entendido, VolatileRead agrega un MemoryBarrier. Sin embargo, esto no garantiza que el segundo hilo pueda leer el valor "nuevo" que escribió el primer hilo. Entonces, aunque esto funciona, creo que, teóricamente, no debería (al menos usar los métodos VolatileRead y VolatieWrite). – Petrakeas

1

Tanto ganar cuando se ejecutan en paralelo.

De la documentación (http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.invoke.aspx): Ejecuta cada una de las acciones proporcionadas, posiblemente en paralelo.

+0

+1 buena captura !!! – Gabber

+3

Eso todavía es extraño. ayb son volátiles y se actualizan antes de verificar el valor en la otra tarea. Eso significa que en el momento en que a está comprobando si b == 1, al menos debe ser 1 y viceversa, por lo que parece que lógicamente, como máximo, uno puede ganar. – GolezTrol

+0

@GolezTrol que tendría sentido, pero a pesar de que se declaran como volátiles, no se utilizan como tales: obtiene/establece sin usar Volatile.Read/Volatile.Write –