Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding non blocking thread synchronization and Thread.MemoryBarrier

In this threading online book: http://www.albahari.com/threading/part4.aspx

theres an example of Thread.MemoryBarrier()

   class Foo
{
  int _answer;
  bool _complete;

  void A()
  {
    _answer = 123;
    Thread.MemoryBarrier();    // Barrier 1
    _complete = true;
    Thread.MemoryBarrier();    // Barrier 2
  }

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

We got a discussion whether there is any thread blocking going on or not?

Im thinking there is some, especially given that

A full fence takes around ten nanoseconds on a 2010-era desktop.

On other hand, full fence is only supposed to disable instructions reodering and caching which by its sound doesn't qualify as thread blocking, (unlike lock where its clear that thread waits for other to release lock before it continues, and is blocked during that time)

About that thread 'block state'. im talking not in terms of whether thread is put into blocked state or not, but whether there is some thread synchronization happening, which means one thread is not able to run while other isn't letting it to do so, by means of MemoryBarrier in this case.

Also Id like to get clear understanding what each barrier achieves. For example Barrier 2 - how exactly it provides freshness guarantee and how is it connected to barrier 3? If someone would explain in detail whats each barrier purpose here( what could possibly go wrong if 1 or 2 or 3 or 4 weren't there) I think id improve my understanding of this greatly.

EDIT: its mostly clear now what 1, 2, and 3 do. However what 4 does that 3 doesn't is still unclear.

like image 749
Valentin Kuzub Avatar asked Aug 30 '11 21:08

Valentin Kuzub


People also ask

What is thread MemoryBarrier?

Synchronizes memory access as follows: The processor executing the current thread cannot reorder instructions in such a way that memory accesses prior to the call to MemoryBarrier() execute after memory accesses that follow the call to MemoryBarrier().

What does blocking mean in threading?

Blocked means execution gets stuck there; generally, the thread is put to sleep by the system and yields the processor to another thread. When a thread is blocked trying to acquire a mutex, execution resumes when the mutex is released, though the thread might block again if another thread grabs the mutex before it can.

How do you sync threads in C#?

We can use C# lock keyword to execute program synchronously. It is used to get lock for the current thread, execute the task and then release the lock. It ensures that other thread does not interrupt the execution until the execution finish.


1 Answers

The fact that instructions take time to execute does not imply that a thread is blocked. A thread is blocked when it is specifically put into a blocked state, which MemoryBarrier() does not do.

The processor instructions that actually prevent instruction reordering and cache flushing take time, because they must wait for the caches to become coherent again. During that time, the thread is still considered running.

Update: So let's take a look at what's actually happening in the example, and what each memory barrier actually does.

As the link says, 1 and 4 ensure that the correct answers are produced. That's because 1 ensures that the answers are flushed into memory, and 4 ensures that the read caches are flushed prior to retrieving the variables.

2 and 3 ensure that if A runs first, then B will always print the answers. Barrier 2 ensures that the write of true is flushed to memory, and barrier 3 ensures that the read cahces are flushed before testing _complete's value.

The cache and memory flushing should be clear enough, so let's look at instruction reordering. The way the compiler, CLR and CPU know they can reorder instructions is by analyzing a set of instructions in sequence. When they see the barrier instruction in the middle of a sequence, they know that instructions can't move across that boundary. That ensures that in addition to cache freshness, the instructions occur in the correct order.

like image 85
dlev Avatar answered Sep 21 '22 05:09

dlev