在Link.TryAdd
方法的dapper代码中,有如下一段代码:
var snapshot = Interlocked.CompareExchange(ref head, null, null);
为什么这是必需的而不是简单的:
var snapshot = head;
这两行都没有改变head
的值,两行都将head
的值赋值给snapshot
。为什么选择第一个而不是第二个?
最佳答案
他们想要进行 volatile 读取,但是没有采用通用类型参数的 Thread.VolatileRead
重载。以这种方式使用 Interlocked.CompareExchange
可获得相同的结果。
他们试图解决的问题是,JIT 编译器可以在认为合适的情况下优化对 temp 的赋值。如果当前线程在一系列操作中使用 head 引用时另一个线程改变了 head 引用,这可能会导致线程问题。
编辑:
问题不在于在 TryAdd
开始时读取了过时值。问题是在第 105 行,他们需要将当前头部与之前的头部进行比较(保存在 snapshot
中)。如果有优化,则没有保存先前值的 snapshot
变量,此时会再次读取 head
。即使 head 可能在第 103 行和第 105 行之间发生变化,CompareExchange
也很有可能成功。结果是如果两个线程同时调用 TryAdd
,列表中的节点将丢失.
关于c# - Interlocked.CompareExchange 在 dapper .net 方法中用于什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11110012/