.NET Volatile.Read/Write和Interlocked范围

时间:2016-04-08 14:14:33

标签: c# .net multithreading memory-barriers

我已多次阅读threading manual及相关的MSDN网页和SO questions。不过,我还不完全理解Volatile.Read/Write和互锁操作是仅适用于相关变量,还是适用于该操作之前/之后的所有读/写操作。

例如,想象一下我有一个数组和一个计数器。

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,并在互锁增量之前设置一个实例字段。隐式完整栅栏是否适用于来自该线程之前的所有读/写,或仅适用于计数器?

我正在实施一个scalable reader/writer scheme,我在Joe Duffy的帖子中找到了以下声明:

  

如果受保护的变量是对堆对象的引用,则每次触摸字段时都需要担心使用读保护。就像锁一样,这种技术不会构成。与简单锁定以外的任何其他操作一样,请谨慎使用此技术;虽然内置的获取和释放屏障可以保护您免受内存模型重新排序的影响,但是您可以使用一些简单的陷阱。

这只是阻止使用低锁构造的一般性陈述,或者某种方式适用于上面的例子吗?

1 个答案:

答案 0 :(得分:2)

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

简短回答是Interlocked.Increment发出一个完整的围栏,它与正在更新的变量无关。我相信Volatile.Write会发出半个围栏。可以从Thread.MemoryBarrier构建半栅栏。当我们说Interlocked.Increment发出完整的栅栏时,意味着在操作之前和之后调用Thread.MemoryBarrierVolatile.Write在写入之前调用Thread.MemoryBarrier,在Volatile.Read之后调用Thread.MemoryBarrier。围栏确定何时可以重新排序内存访问(并且它不是特定于变量的,因为var options = ["lousiana", 'los angeles', 'another'] var userInput = "lo" options.forEach(function(val){ if(val.indexOf(userInput) == 0){ console.log(val.replace(new RegExp('('+userInput+')(.*)', 'gi'), "$1<b>$2</b>")) } }) options.forEach(function(val){ var idx = val.indexOf(userInput) if(idx == 0){ console.log(userInput+'<b>'+val.substring(userInput.length)+'</b>') } })是无参数的)。