3

I modified the program given on Non-Blocking Synchronization as following:

class DemoProg
{
    int _answer;
    bool _complete;

    public void StartDemo()
    {
        Thread t1 = new Thread(A);
        Thread t2 = new Thread(B);
        t1.Start();
        // Thread.Sleep(100); // To ensure that B is called after A.
        t2.Start();
    }

    void A()
    {
        for (int i = 0; i < 1000000; i++)
            _answer = 123;
        Thread.MemoryBarrier();    // Barrier 1
        _complete = true;
        Thread.MemoryBarrier();    // Barrier 2
        Console.WriteLine("Exiting A");
    }

    void B()
    {
        //Thread.Sleep(100);
        Thread.MemoryBarrier();    // Barrier 3
        if (_complete)
        {
            Thread.MemoryBarrier();       // Barrier 4
            Console.WriteLine(_answer);
        }
        Console.WriteLine("Exiting B");
    }
}

The article states that they ensure that if B ran after A, reading _complete would evaluate to true. >> they means memory barriers.

Even if i remove memory barriers, there is no change in output. and it's not making sure that if condition results true.

did I interpret it in wrong way?

Thanks.

Azodious
  • 13,752
  • 1
  • 36
  • 71
  • 3
    Keep in mind that a memory barrier *forces* ordering -- but the same ordering could happen without the memory barrier. The difference is that without the barrier you can't depend on its happening. – Jerry Coffin May 02 '11 at 05:44
  • Yes, got your point. but perhaps i asked question in wrong way. i've updated it. pls clarify now. – Azodious May 02 '11 at 06:09
  • Lets say barrier 1 executes first, then barrier 2 and then if condition. how does it make sure that `_complete` would evaluate to true? – Azodious May 02 '11 at 06:18
  • @Azodious: They don't. A memory barrier only assures against reordering other code in the same thread. As I tried to imply before, on x86 I believe it's a nop (it's mostly for Itanium). In your code, for example, it would ensure that `_complete` isn't set in `A` until after `_answer` has been written. It does not, however, assure you of anything about operations in `B` compared to `A`. – Jerry Coffin May 02 '11 at 06:23
  • Ok, so memory barrier is only about ensuring the reordering of processor instructions. means a programmer can control the instruction execution upto some extent. The article statement `they ensure that if B ran after A, reading _complete would evaluate to true.` is it wrong? or does it mean that B executes after **completion** of A? – Azodious May 02 '11 at 06:37
  • 1
    It means that inside of A, _answer is always written *before* _complete. When B runs, if it finds that _complete is true, then _answer will already have been written -- but it gives no guarantee about whether _complete will be true or not. – Jerry Coffin May 02 '11 at 06:43
  • k .. clear now. so memory barrier in A is making sure that `_complete` is written after `_answer`is updated, even when the reordering of statements occur. i hope i'm getitng it rightly now. – Azodious May 02 '11 at 06:53
  • found a similar question here. http://stackoverflow.com/questions/3556351/why-we-need-thread-memorybarrier – Azodious May 02 '11 at 06:56
  • @Azodious: yes, that's correct. – Jerry Coffin May 02 '11 at 06:57

1 Answers1

1

I talk about this very example here and here.

In a nutshell, the author is correct. Pay very close attention to the statement. In particular, notice that the author says "if B ran after A". He was not saying that the condition will always evaluate true. Instead, the example was contrived to demonstrate one particular nuance of memory barriers.

Furthermore, getting a different result by removing memory barriers will be difficult to reproduce. There are many reasons for this. It is likely due to the environment in which you were running the tests.

Community
  • 1
  • 1
Brian Gideon
  • 47,849
  • 13
  • 107
  • 150