【发布时间】:2013-05-15 18:34:41
【问题描述】:
众所周知,与 Java 的 volatile 不同,.NET 的 volatile 允许使用来自另一个位置的以下 volatile 读取来重新排序 volatile 写入。当出现问题时,建议将MemoryBarier放在它们之间,或者可以使用Interlocked.Exchange代替volatile write。
它可以工作,但MemoryBarier 在高度优化的无锁代码中使用时可能会成为性能杀手。
我想了想,想出了一个主意。我希望有人告诉我我是否走对了路。
所以,思路如下:
我们希望防止这两个访问之间的重新排序:
volatile1 write
volatile2 read
从 .NET MM 我们知道:
1) writes to a variable cannot be reordered with a following read from
the same variable
2) no volatile accesses can be eliminated
3) no memory accesses can be reordered with a previous volatile read
为了防止写入和读取之间不必要的重新排序,我们从刚刚写入的变量中引入了一个虚拟的 volatile 读取:
A) volatile1 write
B) volatile1 read [to a visible (accessible | potentially shared) location]
C) volatile2 read
在这种情况下,B 不能用 A 重新排序,因为它们都访问同一个变量, C 不能用 B 重新排序,因为两个 volatile 读取不能相互重新排序,并且传递性 C 不能用 A。
还有问题:
我说的对吗?这种虚拟的易失性读取可以用作这种情况下的轻量级内存屏障吗?
【问题讨论】:
-
在“高度优化的无锁代码”中使用
volatile似乎很奇怪。您的易失性读取需要花费一百个或更多周期?因此,易失性读取的成本大约是非竞争锁的一半。可能还不止于此。我的建议是重新考虑您的设计以避免不稳定。 bluebytesoftware.com/blog/2010/12/04/SayonaraVolatile.aspx -
@JimMischel 在 ARM 上(您的评论在那里有效)。在 x86 上,到目前为止,它只会阻止编译器/JIT 重新排序和消除访问。它不会导致发出不同的指令。
-
@Jim Mischel:我的问题是关于加载获取和存储释放障碍。 Volatile 只是一种强制执行它们的 C# 方式。顺便说一句,在 4.5 中,我们可以使用 Volatile 类的 Read 和 Write 方法代替 volatile 关键字。
标签: c# .net performance volatile memory-model