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?
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.
See more on this question at Stackoverflow