编写的代码将从 CLR2.0 开始工作,因为 CLR2.0 内存模型保证所有商店都有发布语义.
发布语义:确保围栏前没有任何负载或储存物品
将在栅栏后移动。之后的说明之前可能仍然会发生
栅栏。(摘自CPOW https://rads.stackoverflow.com/amzn/click/com/032143482X第 512 页)。
这意味着在分配类引用之后不能移动构造函数初始化。
乔·达菲在他的关于同一主题的文章 http://joeduffyblog.com/2007/11/10/clr-20-memory-model/.
规则 2:所有存储都具有发布语义,即不能加载或存储
继一后移动。
还有万斯·莫里森的文章在这里 https://msdn.microsoft.com/en-us/magazine/cc163715.aspx证实了同样的情况(第 4 节:延迟初始化)。
与所有移除读锁的技术一样,图 7 中的代码
依赖于强写顺序。例如,这段代码将是
在 ECMA 内存模型中不正确,除非将 myValue 设为易失性
因为初始化 LazyInitClass 实例的写入可能是
延迟到写入 myValue 之后,允许客户端
GetValue 读取未初始化状态。在 .NET Framework 2.0 中
模型,代码可以在没有易失性声明的情况下工作。
从 CLR 2.0 开始,写入保证按顺序发生。 ECMA 标准中没有指定,只是 Microsoft 的 CLR 实现提供了这种保证。如果您在 CLR 1.0 或任何其他 CLR 实现中运行此代码,你的代码可能会被破坏.
这一变化背后的故事是:(来自CPOW https://rads.stackoverflow.com/amzn/click/com/032143482X第516页)
当CLR 2.0移植到IA64时,其最初的开发已经
发生在 X86 处理器上,因此它的处理能力较差
任意存储重新排序(IA64 允许的)。也是如此
大多数由非 Microsoft 开发人员编写的针对 .NET 的代码
针对 Windows
结果是框架中的很多代码在运行时崩溃了
IA64,特别是与臭名昭著的双重检查有关的代码
锁定模式突然无法正常工作。我们会检查这个
在本章后面的模式的背景下。但总而言之,
如果商店可以传递其他商店,请考虑这一点:一个线程可能
初始化私有对象的字段,然后发布对的引用
它位于共享位置;因为商店可以四处移动,另一个
线程可能能够看到对该对象的引用,读取它,并且
但在字段仍处于未初始化状态时查看它们。
这不仅影响现有代码,还可能违反类型系统
属性,例如 initonly 字段。
因此 CLR 架构师决定通过发布来增强 2.0
IA64 上的所有商店都作为释放栅栏。这给了所有 CLR 程序
更强的记忆模型行为。这确保了程序员不需要
必须担心微妙的竞争条件,这些条件只会在
在一个不起眼、很少使用且昂贵的架构上进行实践。
注意乔·达菲说他们通过将 IA64 上的所有商店作为释放栅栏来强化 2.0 这并不意味着其他处理器可以对其重新排序。其他处理器本身本质上提供了store-store(store后面跟着store)不会被重新排序的保证。所以 CLR 不需要明确保证这一点。