views:

185

answers:

5

In the following code sample, does the memory barrier in FuncA is required to ensure that the most up-to-date value is read?

class Foo
{
   DateTime m_bar;

   void FuncA() // invoked by thread X
   {
      Thread.MemoryBarrier(); // is required?
      Console.WriteLine(m_bar);
   }

   void FuncB() // invoked by thread Y
   {
       m_bar = DateTime.Now;
   }       
}

EDIT: If not, how can I ensure that FuncA will read the most recent value? (I want to make sure that the recent value is actually store in the processor's cache) [wihout using locks]

+2  A: 

Looks like a big "No" to me. Thread.MemoryBarrier() only syncs up memory access within the thread that implemented it.

From MSDN:

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.

JustLoren
+2  A: 

I suggest you store Datetime as number of ticks (it is of type "long", i.e. Int64), you can easily transform from ticks (new DateTime (ticks)) and to ticks (myDateTime.Ticks). Then you can use Interlocked.Read to read value and Interlocked.Exchange to write value in fast non-locking operations.

Dmitry
That's the only way to do this without using sync blocks (Monitor.Enter and Exit, aka lock(foo)), since Interlocked only works with long or ints.
Yann Schwartz
An exemple here: http://stackoverflow.com/questions/1531668/thread-safe-datetime-update-using-interlocked
Yann Schwartz
A: 

Yes, the memory barrier is needed so that you can get the most up to date value.

If the memory barrier is not present then it is possible for thread X to read the value of m_bar from its own cache line while that value hasn't been written back to main memory (the change has been make local to Thread Y). You can achieve the same effect by declaring the variable as volatile:

The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access. Using the volatile modifier ensures that one thread retrieves the most up-to-date value written by another thread.

A good entry on that matter (probably the best) is this one by Joe Duffy: Volatile reads and writes, and timeliness

Jorge Córdoba
Interestingly the description for MemoryBarrier differ in .NET 2.0 and .NET 3.5 2.0 => "Synchronizes memory. In effect, flushes the contents of cache memory to main memory, for the processor executing the current thread." 3.5 ==> "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."
Jorge Córdoba
A: 

A memory barrier does infact the same thing as wat locking does, guarantee the field will get its latest value from memory on entering the lock and be written to memory before exiting the lock.
Making sure a field's value is always read or written to memory and never optimized by reading or writing it first to the cpu's cache can also be achieved by using the volatile keyword.
Unless primitive integral types and reference types DateTime cannot be cached in CPU registers ad so need not (and cannot) be declared with the volatile keyword.

Mez
A: 

This actually doesn't matter since on 32bit architectures one can get a torn read in such situation