为什么这个赋值不是线程安全的?

本文关键字:线程 安全 赋值 为什么 | 更新日期: 2023-09-27 17:49:37

我一直在读Joseph Albahari写的关于线程的书:
http://www.albahari.com/threading/

在第2部分中,我发现了这个例子:
http://www.albahari.com/threading/part2.aspx _When_to_Lock

下面是前面提到的例子:

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

线程安全版本:

class ThreadSafe
{
  static readonly object _locker = new object();
  static int _x;
  static void Increment() { lock (_locker) _x++; }
  static void Assign()    { lock (_locker) _x = 123; }
}
我不明白为什么Assign方法不是线程安全的。整数赋值不应该是32位和64位架构上的原子操作吗?

为什么这个赋值不是线程安全的?

赋值是atomic,因为任何读线程都将看到123或前一个值-而不是某个中间值。但是,在存在两个内存屏障(写线程中的写内存屏障和读线程中的读内存屏障)之前,不能保证线程将看到新值。

如果您有两个这样的线程(在将_x设置为公共或内部之后,这样当然可以从其他类型中读取它-或者使用ThreadSafe类中的代码):

// 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");

…不能保证线程2会完成,因为线程2可能不会"看到"线程1的赋值。