Joe Duffy提出了描述CLR 2.0+内存模型的6条规则(实际实现,而非任何ECMA标准)。我正在尝试理解这些规则,主要是作为一种自我解释的方式,但如果我的逻辑有误,至少在这里有人能够在它引起麻烦之前抓住它。
- 规则1:加载和存储之间的数据依赖关系永远不会被违反。
- 规则2:所有存储都具有释放语义,即在其后不能移动任何加载或存储。
- 规则3:所有易失性加载都是获取的,即在其前不能移动任何加载或存储。
- 规则4:不得跨越完整屏障(例如Thread.MemoryBarrier、lock acquire、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是易失性的,则负载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之外的所有内容。有人想启发我(或者纠正我或者添加任何关于上述内容的东西吗?)