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

【Interlocked|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能更多的并行。

    推荐阅读