在 SO 上有很多关于Interlocked
vs. volatile
here 的问题,我理解并知道volatile
(不重新排序,总是从内存中读取等)的概念,并且我知道Interlocked
它是如何执行原子操作的。
但我的问题是这样的:假设我有一个从多个线程读取的字段,它是某种引用类型,比如说:public Object MyObject;
。我知道,如果我对它进行比较交换,如下所示:Interlocked.CompareExchange(ref MyObject, newValue, oldValue)
互锁保证只写入引用newValue
的内存位置ref MyObject
,如果ref MyObject
和oldValue
当前引用同一个对象。
但是阅读呢?是否Interlocked
保证操作成功MyObject
后读取的任何线程CompareExchange
都会立即获得新值,还是我必须标记MyObject
为volatile
确保这一点?
我想知道的原因是我已经实现了一个无锁链表,当你向它添加一个元素时,它会不断更新自身内部的“头”节点,如下所示:
[System.Diagnostics.DebuggerDisplay("Length={Length}")]
public class LinkedList<T>
{
LList<T>.Cell head;
// ....
public void Prepend(T item)
{
LList<T>.Cell oldHead;
LList<T>.Cell newHead;
do
{
oldHead = head;
newHead = LList<T>.Cons(item, oldHead);
} while (!Object.ReferenceEquals(Interlocked.CompareExchange(ref head, newHead, oldHead), oldHead));
}
// ....
}
现在Prepend
成功后,是否保证读取的线程head
获得最新版本,即使它没有标记为volatile
?
我一直在做一些实证测试,它似乎工作正常,我在这里搜索过但没有找到明确的答案(一堆不同的问题和评论/答案都说相互矛盾的事情)。