有模式(例如这里的模式C#/CLR: MemoryBarrier and torn reads) 可以执行撕裂读取,但如果可能发生撕裂读取,则永远不要使用结果值。
这是C#中未定义的行为吗?
相关:我怎样才能确定这是否是未定义的行为?
我的理解(纠正我,如果我错了)是在C ++ 11中这将是未定义的行为,因为它不是由C ++ 11中添加的内存模型定义的(在旧版本中所有多个 - 线程是特定于实现的行为)。从理论上讲,我可以从规范中确定这一点。
我尝试为C#做这个并且失败了。我在规范中找不到内存模型。下面是我通过C#语言规范(http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf)尝试跟踪在可能存在数据竞争的情况下将一个结构分配给另一个结构的语义失败的一些注释(一个读者复制,一个作者写作)被复制的数据)。在任何场景中,我都找不到分配或读取任何变量的语义。要么我错过了某些东西(几乎可以肯定是这种情况),要么使用变量是未定义的行为。
C#语言规范说明什么类型是原子的,但从来没有用于原子和非原子读写的测量:
12.5变量引用的原子性
以下数据类型的读写应为原子:bool,char,byte,sbyte,short, ushort,uint,int,float和reference类型。另外,读取和 在上一个列表中写入具有基础类型的枚举类型 也应该是原子的。其他类型的读写,包括long, ulong,double和decimal,以及用户定义的类型,不一定是 原子。除了为此目的设计的库函数, 不能保证原子读 - 修改 - 写,例如在这种情况下 增量或减量。
它没有说" atomic" (它没有定义)这里暗示任何围栏(所以我假设没有),但更相关的是这个问题,它甚至没有定义读写操作(这在多线程程序中是非常重要的)。
看14.14.1 Simple assignment
,这似乎是写规范的范围(解释" x = y"):
y的评估和转换产生的值存储在由。给出的位置 评估x。
8.3 Variables and parameters
州:
在获得其值之前,应指定一个变量。
但未定义获取值。我在哪里看到读数产生的规范(人们会假设你在单线程案例中写的最后一件事,所以我无法在规范中找到它。)
10.10 Execution order
似乎不必要地限制(与下面链接的MSDN文章中使用的正常获取和释放语义相比)易于写入(没有写入可以在任何方向上移动到对volatile的引用)约束读取(它们可以在易失性操作中向两个方向移动。它也没有提到Thread.MemoryBarrier(谁的文档似乎阻止了处理器,但没有编译器重新排序,所以它太弱了。)它也没有引用什么加载从变量/字段意味着,那里有许多讨厌的offtopic问题,但没有答案。
我已经阅读了我能找到的相关规范的所有部分。无处读取字段/内存/变量(看起来像#34;变量"这里是正确的术语)定义。
也许在语言规范的某个地方有一个读取/加载和写入/存储变量行为的规范(又名:内存模型),但如果有(我无法找到它),它没有引用" atomic" (我搜索它是原子的:第12.5节是唯一的用途)。我不知道如何定义任何C#代码,所以很明显我错过了一些东西:我不认为有效的C#实现可能会退出(因为它是未定义的行为!)on on任何读取或写入的值。
如果多线程(甚至可能是单线程)C#在没有内存模型的情况下实际上是非常不明确的,那么有没有可以查看特定实现的规范?例如:如果C#没有定义读写的语义,也许微软的各种C#编译器(现在至少有3个)提供规范,Mono也是如此?这在任何实现中都是安全的吗?什么是好的方法?
也许有一些非正式的(不在规范中)规则被认为是安全的(所有主要实现都遵守)?这将是可怕的,但如果我们得到的全部,我会接受它。
我发现这篇文章声称是关于C#内存模型,但它是特定于实现的(参考CLR),并未涵盖相关案例。它还提供了一个很好的清晰解释,说明我喜欢的挥发性语义(C ++ 11风格获得一个版本),但在某些方面更强大,而在10.10 Execution order
以外的语言更弱spec,所以我认为错了:https://msdn.microsoft.com/magazine/jj863136
这篇文章似乎有很多关于C#内存模型与C ++ 11的比较的好信息,但据我所知,它还没有涵盖这个特定的问题:http://blog.alexrp.com/2014/03/30/dot-net-atomics-and-memory-model-semantics/
关于重新排序问题的好文章。最后的更新提到"易失性读取可以相对于易失性写入及时向后移动"这与规范中的10.10 Execution order
不一致,但同意大多数人认为语义应该是什么(意味着它与MSDN文章和Volatile类一致,但据我所知,不是关键字):http://blog.coverity.com/2014/03/12/can-skip-lock-reading-integer/#.VoSyfhXhDGg
从快速浏览一下,本文主要介绍易失性及其如何防止冗余负载消除以及为何需要:https://blogs.msdn.microsoft.com/ericlippert/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three/