I am running a simple code snippet on .net framework 45:
public class Program
{
public static /*volatile*/ int A = 1;
public static int B = 1;
public static bool ReadAndCheck()
{
var a = A;
// Interlocked.MemoryBarrier(); full memory barrier works as expected
var b = B;
return a > b;
}
public static void First()
{
while (true)
{
e.WaitOne();
if (ReadAndCheck())
{
Console.WriteLine("reordering");
}
e.Set();
}
}
private static readonly AutoResetEvent e = new AutoResetEvent(false);
public static void Second()
{
while (true)
{
A = 1;
B = 1;
e.Set();
B = 2;
A = 2;
e.WaitOne();
}
}
public static void Main()
{
new Thread(First).Start();
new Thread(Second).Start();
Console.ReadKey();
}
}
And I get lots of "reordering" messages in my console. I assume that it is an instruction reordering that the CPU does. I've discovered that if I add a Interlocked.MemoryBarried
in the First method(it's commented there), the code works fine and there are no "reordering" messages in my console. Also, I think it happens because var a = A;
and var b = B;
instructions are reordered between themselves(first we read B, then A) and the memory barrier ensures "correct" sequence of these instructions
Then, as far as I understand, volatile field "A" is sufficient because it seems to prevent var b = B;
being executed before var a = A
. But, in fact, it is not true, and I keep getting "error" messages. Could anyone clarify this behavior, please?
UPD:
I would expect half-barrier to work correctly if made A
volatile. As no instruction below volatile read can be moved above volatile read. It means, that var b = B
will never be moved above var a = A
.
Feel free to correct me if I am wrong