[英]Understanding CLR 2.0 Memory Model
Joe Duffy给出了描述CLR 2.0+内存模型的6条规则 (它是实际的实现,而不是任何ECMA标准)我正在写下我试图解决这个问题的方法,主要是作为橡皮避短的一种方式,但如果我犯了一个错误在我的逻辑中,至少有人能够在它引起我悲伤之前抓住它。
我试图理解这些规则。
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是波动的怎么办? 我没有看到禁止执行上述优化的规则中的任何内容。 这并不违反双重检查锁定,因为两个相同条件之间的锁定()可防止负载移动到相邻位置,并且根据规则6,这是唯一可以消除它们的时间。
所以我认为除了规则5之外我都理解了。 有人想启发我(或纠正我或添加上述任何东西吗?)
Joe Duffy讨论了Windows上并发编程 pp517-18的规则5:
作为可能引入负载的示例,请考虑以下代码:
MyObject mo = ...;
int f = mo.field;
if (f == 0)
{
// do something
Console.WriteLine(f);
}
如果初始读取mo.field到变量f之间的时间段以及随后在Console.WriteLine中使用f的时间足够长,编译器可能会认为重新读取mo.field两次会更有效。 ...如果mo是一个堆对象并且线程同时写入mo.field,那么这样做会有问题。 if-block可能包含假定读入f的值保持为0的代码,并且读取的引入可能会破坏这种假设。 除了禁止将此用于volatile变量之外,.NET内存模型还禁止将其用于引用GC堆内存的普通变量。
我在博客上写了一个重要的地方 :举办活动的标准模式。
EventHandler handler = MyEvent;
if (handler != null)
handler(this, EventArgs.Empty);
为了防止在单独的线程上删除事件处理程序的问题,我们读取MyEvent
的当前值,并且只有在该委托非空时才调用事件处理程序。
如果可以引入从堆中读取,则编译器/ JIT可能会决定再次读取MyEvent
更好,而不是使用本地,这会引入竞争条件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.