1

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

DANTALION
  • 49
  • 2
  • 1
    `volatile` is only a half-barrier, `MemoryBarrier` is full. It's much easier to use `Interlocked.Exchange` etc which automatically issues a full barrier – Charlieface Feb 23 '21 at 02:03
  • Does this answer your question? [Half - fences and full fences?](https://stackoverflow.com/questions/10589654/half-fences-and-full-fences) – Charlieface Feb 23 '21 at 02:05
  • @Charlieface, thanks, but I can't figure out why "volatile" is not sufficient. I have updated the question with a more detailed explanation – DANTALION Feb 23 '21 at 06:28
  • What happens if `B` is `volatile` as well? I.e. only `volatile read/writes are synced, not other variables – Charlieface Feb 23 '21 at 10:19
  • The same behavior ;) I am running on .net framework 4.5 in Release mode – DANTALION Feb 23 '21 at 10:35
  • Judging by the link I mentioned, and various other places, `volatile` does not guarantee the cache line for *different locations* is cleared in order, only that the sequence of reads and write *instructions* are in the right order – Charlieface Feb 23 '21 at 11:51
  • http://joeduffyblog.com/2010/12/04/sayonara-volatile/ and also http://joeduffyblog.com/2008/06/13/volatile-reads-and-writes-and-timeliness/ – Slugart Feb 23 '21 at 12:28

0 Answers0