Interlocked 本人水平有限-翻译的很烂

 当在加锁释放代码下读写字段时,使用内存屏障也不总是够用的,操作64位字段,增值,减量需要使用Interlocked类。Interlocked类也提供给了Exchange和CompareExchange方法,后者可以是锁模式下,使用一点额外的代码实现读写字段操作。

 
在潜在的处理器上,如果一个语句以单一可视的指令执行在处理器上,那么它本质上是原子性的。严格的原子性排除了抢占的可能性。对32位或更少位数的字段的简单读写总是原子性的,但只有在64运行环境中,对64位的字段操作才保证原子性,包含多个读写操作的语句不是原子性的。
 
class Atomicity
{
  static int _x, _y;
  static long _z;
 
  static void Test()
  {
    long myLocal;
    _x = 3;             // 原子性
    _z = 3;             // Nonatomic on 32-bit environs (_z is 64 bits)
    myLocal = _z;       // Nonatomic on 32-bit environs (_z is 64 bits)
    _y += _x;           // Nonatomic (read AND write operation)
    _x++;               // Nonatomic (read AND write operation)
  }
}
在32位环境上读写64位字段不是原子性的,因为它要执行2个分开的指令,每个对32位内存地址。所以,如果线程x读取64为值,而线程Y正在更新它,线程X可能以按位合并了新值和旧值。(撕裂的读取)。
编译器实现单目运算符类似x++通过读取变量,处理,然后回写。
看下面的代码
class ThreadUnsafe
{
  static int _x = 1000;
  static void Go() { for (int i = 0; i < 100; i++) _x--; }
}
 
暂时不考虑内存屏障的问题,你可能期望10个线程并发运行Go,——x最终为0.然而,这个不保证的,因为竞争条件可能在获取——x的当前值的时候,一个线程抢占另一个线程,减去它,然后回写,导致一个过期的值被回写。当然,你可以通过用lock语句来包裹这个非原子操作符对付这个问题。事实上,锁如果始终应用的话,模拟了原子性。但是Interlocked类提供了更加简单快速的解决方案。
 
class Program
{
  static long _sum;
 
  static void Main()
  {                                                             // _sum
    // Simple increment/decrement operations:
    Interlocked.Increment (ref _sum);                              // 1
    Interlocked.Decrement (ref _sum);                              // 0
 
    // Add/subtract a value:
    Interlocked.Add (ref _sum, 3);                                 // 3
 
    // Read a 64-bit field:
    Console.WriteLine (Interlocked.Read (ref _sum));               // 3
 
    // Write a 64-bit field while reading previous value:
    // (This prints "3" while updating _sum to 10)
    Console.WriteLine (Interlocked.Exchange (ref _sum, 10));       // 10
 
    // Update a field only if it matches a certain value (10):
    Console.WriteLine (Interlocked.CompareExchange (ref _sum,
                                                    123, 10);      // 123
 
  }
}
所有的这些Interlocked的方法产生了一个full fence。因此,你通过Interlocked访问的字段不再需要额外的屏障,除非他们访问你程序中的其他没有使用锁的地方。Interlocked的数学操作符限制在Increment, Decrement, 和Add。如果你想乘,或者执行其他计算,您能通过CompareExchange方法(通常和spin-waiting联合)。
 
Interlocked的方法通常需要10纳秒,是uncontended锁的一半,此外,它不需要额外的上下文切换所带来的开销。另一面,使用Interlocked在多个递归上不如循环中获得一个单一的锁有效。尽管Interlocked能更多的并行。

你可能感兴趣的:(Interlocked 本人水平有限-翻译的很烂)