.NET Volatile.Read/Write 和 Interlocked 作用域

.NET Volatile.Read/Write and Interlocked scope

threading manual and relevant MSDN pages and SO questions我已经读了好几遍了。尽管如此,我还是不完全理解 Volatile.Read/Write 和互锁操作是否仅适用于相关变量,或者所有 read/writes before/after 操作。

例如,假设我有一个数组和一个计数器。

long counter = 0;
var values = new double[1000000];

values[42] = 3.1415;
// Is this line needed instead of simple assignment above,
// or the implicit full-fence of Interlocked will guarantee that 
// all threads will see the values[42] after interlocked increment?
//Volatile.Write(ref values[42], 3.1415);
Interlocked.Increment(ref counter);

互锁增量是否保证与我使用 Volatile.Write(ref values[42], 3.1415); 而不是 values[42] = 3.1415; 相同的结果。

如果我有一个引用类型数组怎么办,例如一些 POCO,并在互锁增量之前设置一个实例字段。隐式完全围栏是否适用于它之前的那个线程的所有 read/writes,还是仅适用于计数器?

我正在实施 scalable reader/writer scheme,我在 Joe Duffy post 中发现了以下语句:

If the variables protected are references to heap objects, you need to worry about using the read protection each time you touch a field. Just like locks, this technique doesn’t compose. As with anything other than simple locking, use this technique with great care and caution; although the built-in acquire and release fences shield you from memory model reordering issues, there are some easy traps you can fall into.

这只是一个不鼓励使用低锁结构的一般性陈述,还是以某种方式适用于上面的示例?

您可能缺少的是对栅栏的理解。这是阅读它们的最佳资源:http://www.albahari.com/threading/part4.aspx

简短的回答是 Interlocked.Increment 发出一个完整的栅栏,它独立于它正在更新的变量。我相信 Volatile.Write 问题半篱笆。可以从 Thread.MemoryBarrier 构建半个栅栏。当我们说 Interlocked.Increment 发出完整的栅栏时,这意味着 Thread.MemoryBarrier 在操作前后被调用。 Volatile.Write 在写入前调用 Thread.MemoryBarrier,在写入后调用 Volatile.Read。栅栏确定何时可以重新排序内存访问(并且它不是特定于变量的,因为 Thread.MemoryBarrier 是无参数的)。