Why is this assignment not thread safe?

I've been reading this book from Joseph Albahari about threading:
http://www.albahari.com/threading/

In Part 2, I found this example:
http://www.albahari.com/threading/part2.aspx#_When_to_Lock

Here is the aforementioned example:

class ThreadUnsafe
{
  static int _x;
  static void Increment() { _x++; }
  static void Assign()    { _x = 123; }
}

Thread-safe version:

class ThreadSafe
{
  static readonly object _locker = new object();
  static int _x;

  static void Increment() { lock (_locker) _x++; }
  static void Assign()    { lock (_locker) _x = 123; }
}

I couldn't understand why Assign method is not thread safe. Shouldn't integer assignment be atomic operation on both 32- and 64-bit architectures?

Jon Skeet
people
quotationmark

The assignment is atomic in that any reading thread will either see 123 or the previous value - not some intermediate value. However, there's no guarantee that a thread will see the new value until there have been two memory barriers: a write memory barrier in the writing thread, and a read memory barrier in the reading thread.

If you had two threads like this (after making _x public or internal, so that it could be read from other types of course - or with the code in the ThreadSafe class anyway):

// Thread 1
Console.WriteLine("Writing thread starting");
ThreadSafe.Assign();
Console.WriteLine("Writing thread done");


// Thread 2
Console.WriteLine("Reading thread starting");
while (ThreadSafe._x != 123)
{
    // Do nothing
}
Console.WriteLine("Reading thread done");

... there's no guarantee that thread 2 would ever finish, because thread 2 might not "see" the assignment from thread 1.

people

See more on this question at Stackoverflow