Interlocked.Exchange和Volatile.Write有什么区别?
两种方法都会更新某些变量的值。有人可以总结何时使用它们吗?
http://msdn.microsoft.com/ru-ru/library/bb337971 和http://msdn.microsoft.com/en-us/library/gg712713.aspx
特别是我需要更新我的数组的双项,我希望另一个线程看到最新的值。什么是首选? Interlocked.Exchange(ref arr[3], myValue)
或Volatile.Write(ref arr[3], info);
其中arr
被声明为double
?
=============================================== ============================= 真实的例子,我声明像这样的双数组:
private double[] _cachedProduct;
在一个帖子中我更新它:
_cachedProduct[instrumentId] = calcValue;
...
are.Set();
在另一个线程中我读了这个数组:
while(true) {
are.WaitOne();
...
result += _cachedProduct[instrumentId];
...
}
对我而言,它的工作正常。但是,要确保“它始终有效”,无论看起来如何,我都应添加Volatile.Write
或Interlocked.Exchange
。因为双重更新不能保证是原子http://msdn.microsoft.com/en-us/library/aa691278%28VS.71%29.aspx
在回答这个问题时,我希望看到Volatile和Interlocked类的详细比较。为什么我们需要2节课?哪一个以及何时使用?
答案 0 :(得分:11)
Interlocked.Exchange使用保证原子操作的处理器指令。
Volatile.Write也是如此,但它还包括一个内存屏障操作。 由于Windows 8上支持ARM处理器,我认为微软在DotNet 4.5上添加了Volatile.Write。英特尔和ARM处理器在内存操作重新排序方面存在差异。
在Intel上,您可以保证内存访问操作的执行顺序与它们的顺序相同,或者至少不会重新排序写操作。
来自英特尔®64和IA-32架构软件开发人员手册,第8章:
8.2.2 P6及更近期处理器系列中的内存排序英特尔酷睿2双核,英特尔凌动,英特尔酷睿双核,奔腾4和P6系列 处理器还使用处理器排序的内存订购模型 进一步定义为“使用存储缓冲区转发命令写入”。 该模型的特征如下。
在ARM上,您没有这种保证,因此需要内存屏障。可以在此处找到解释此问题的ARM博客:http://blogs.arm.com/software-enablement/594-memory-access-ordering-part-3-memory-access-ordering-in-the-arm-architecture/
在您的示例中,由于不保证使用double的操作是原子操作,我建议使用锁来访问它。请记住,在读取和设置值时,必须对代码的两个部分使用锁定。
更完整的示例会更好地回答您的问题,因为不清楚设置这些值后会发生什么。对于向量,如果您有比读者更多的读者,请考虑使用ReaderWriterLockSlim对象:http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx
线程数和读/写频率可以显着改变锁定策略。