Si entiendo el significado de volátil y MemoryBarrier correctamente que el programa siguiente nunca debe poder mostrar ningún resultado.¿Por qué los volátiles y MemoryBarrier no impiden el reordenamiento de operaciones?
Captura el reordenamiento de las operaciones de escritura cada vez que lo ejecuto. No importa si lo ejecuto en Depurar o Liberar. Tampoco importa si lo ejecuto como aplicación de 32 bits o 64 bits.
¿Por qué sucede?
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FlipFlop
{
class Program
{
//Declaring these variables as volatile should instruct compiler to
//flush all caches from registers into the memory.
static volatile int a;
static volatile int b;
//Track a number of iteration that it took to detect operation reordering.
static long iterations = 0;
static object locker = new object();
//Indicates that operation reordering is not found yet.
static volatile bool continueTrying = true;
//Indicates that Check method should continue.
static volatile bool continueChecking = true;
static void Main(string[] args)
{
//Restarting test until able to catch reordering.
while (continueTrying)
{
iterations++;
var checker = new Task(Check);
var writter = new Task(Write);
lock (locker)
{
continueChecking = true;
checker.Start();
}
writter.Start();
checker.Wait();
writter.Wait();
}
Console.ReadKey();
}
static void Write()
{
//Writing is locked until Main will start Check() method.
lock (locker)
{
//Using memory barrier should prevent opration reordering.
a = 1;
Thread.MemoryBarrier();
b = 10;
Thread.MemoryBarrier();
b = 20;
Thread.MemoryBarrier();
a = 2;
//Stops spinning in the Check method.
continueChecking = false;
}
}
static void Check()
{
//Spins until finds operation reordering or stopped by Write method.
while (continueChecking)
{
int tempA = a;
int tempB = b;
if (tempB == 10 && tempA == 2)
{
continueTrying = false;
Console.WriteLine("Caught when a = {0} and b = {1}", tempA, tempB);
Console.WriteLine("In " + iterations + " iterations.");
break;
}
}
}
}
}
b/c este es su propia idea. Las barreras de memoria (escritura) solo aseguran que todas las operaciones hasta el momento se limpian, por lo tanto, las siguientes son parte de la barrera. – bestsss
Lo más interesante de su código es que eliminar todas las líneas 'Thread.MemoryBarrier();' arregla su problema =) – Mikant
@Mikant: No, eso no soluciona el problema. Simplemente lo hace muy poco probable. Déjalo funcionar durante unos días y aún podría suceder. –