Joe Duffy,给出了描述 CLR 2.0+ 内存模型的 6 条规则(它是实际实现,不是任何 ECMA 标准)按照我的逻辑,至少这里有人能够在它让我伤心之前抓住它。
- 规则 1:永远不会违反加载和存储之间的数据依赖关系。
- 规则 2:所有存储都有释放语义,即没有加载或存储可以在一个之后移动。
- 规则 3:获取所有易失性负载,即任何负载或存储都不能移动到一个之前。
- 规则 4:任何加载和存储都不能跨越全屏障(例如 Thread.MemoryBarrier、锁获取、Interlocked.Exchange、Interlocked.CompareExchange 等)。
- 规则 5:可能永远不会引入堆的加载和存储。
- 规则 6:只有在合并来自/到同一位置的相邻加载和存储时,才能删除加载和存储。
我试图理解这些规则。
x = y
y = 0 // Cannot move before the previous line according to Rule 1.
x = y
z = 0
// equates to this sequence of loads and stores before possible re-ordering
load y
store x
load 0
store z
看这个,似乎加载 0 可以移动到加载 y 之前,但商店可能根本不会重新排序。因此,如果一个线程看到 z == 0,那么它也会看到 x == y。
如果 y 是 volatile,则加载 0 不能在加载 y 之前移动,否则可能。不稳定的商店似乎没有任何特殊属性,没有商店可以相互重新订购(这是一个非常强的保证!)
完整的障碍就像沙中的一条线,装载和存储无法移动。
不知道第 5 条是什么意思。
我猜规则 6 意味着如果你这样做:
x = y
x = z
然后,CLR 可以删除对 y 的加载和对 x 的第一次存储。
x = y
z = y
// equates to this sequence of loads and stores before possible re-ordering
load y
store x
load y
store z
// could be re-ordered like this
load y
load y
store x
store z
// rule 6 applied means this is possible?
load y
store x // but don't pop y from stack (or first duplicate item on top of stack)
store z
如果 y 不稳定怎么办?我在规则中看不到任何禁止执行上述优化的内容。这并不违反双重检查锁定,因为两个相同条件之间的 lock() 可以防止负载移动到相邻位置,并且根据规则 6,这是唯一可以消除它们的时间。
所以我想我理解除了规则 5 之外的所有内容。任何人都想启发我(或纠正我或在上述任何内容中添加一些内容?)