C#强制执行语句的顺序

我的问题是关于C#中执行保证的顺序(通常可能是.Net)。 我给出了一些我知道要比较的Java示例。

对于Java(来自“Java Concurrency in Practice”)

无法保证一个线程中的操作将按程序给出的顺序执行,只要在该线程内无法检测到重新排序 – 即使重新排序对其他线程是明显的。

所以代码

y = 10; x = 5; a = b + 10; 

可能实际上指定a = b + 10在指定y = 10之前

在Java中(来自同一本书)

当线程A启动由同一个锁保护的同步块时,线程A在同步块之前或之前执行的所有内容都对线程B可见。

所以在Java中

  y = 10; synchronized(lockObject) { x = 5; } a = b + 10; 

保证y = 10和x = 5都在a = b + 10之前运行(我不知道y = 10是否保证在x = 5之前运行)。

C#代码对C#语句的执行顺序有什么保证

  y = 10; lock(lockObject) { x = 5; } a = b + 10; 

我特别感兴趣的答案可以提供明确的参考或其他一些非常有意义的理由,因为这样的保证很难测试,因为它们是关于允许编译器做什么的,而不是它每次都做什么,因为当它们失败时当线程以错误的顺序命中时,你将很难重现间歇性错误。

ISO 23270:2006 – 信息技术 – 编程语言-C# ,§10.10说(我引用):

10.10执行顺序执行应继续进行,以便在关键执行点保留每个执行线程的副作用。 副作用定义为易失性字段的读取或写入,对非易失性变量的写入,对外部资源的写入以及抛出exception。 应保留这些副作用的顺序的关键执行点是对volatile字段(第17.4.3节), lock 语句(第15.12节)以及线程创建和终止的引用。 实现可以自由更改C#程序的执行顺序,但受以下限制:

  • 数据依赖性保留在执行的线程中。 也就是说, 计算每个变量的值,就好像线程中的所有语句都以原始程序顺序执行一样。 (强调我的)。

  • 保留初始化排序规则(第17.4.4节,第17.4.5节)。

  • 关于易失性读写(第17.4.3节),保留了副作用的顺序。 此外,如果某个实现可以推断出该表达式的值未被使用并且不产生所需的副作用(包括通过调用方法或访问volatile字段而导致的任何副作用),则实现不需要评估表达式的一部分。 当程序执行被异步事件(例如另一个线程抛出的exception)中断时,不能保证可观察的副作用在原始程序顺序中可见。

其他CLI标准同样可以从ISO 免费获得

  • ISO 23271:2006 – *信息技术 – 公共语言基础结构(CLI)分区I至VI
  • ISO 23272:2006 – 信息技术 – 公共语言基础设施(CLI) – 从分区IV XML文件派生的信息技术报告

但是如果你担心multithreading问题,你需要深入研究标准并理解关于primefaces性的规则。 并非每项操作都必须是primefaces的。 如果您是multithreading并且调用引用除局部变量(例如,实例或类(静态)成员)之外的任何内容的方法而不通过lock ,互斥体,信号量或其他一些序列化技术进行序列化访问,那么您将自己开放给竞争条件。

我担心你甚至会问这个,但是你问过。

 y = 10; Thread.MemoryBarrier(); x = 5; Thread.MemoryBarrier(); a = b + 10; Thread.MemoryBarrier(); // ... 

来自msdn

按如下方式同步内存访问:执行当前线程的处理器无法重新排序指令,使得在调用MemoryBarrier之前的内存访问在对MemoryBarrier的调用之后的内存访问之后执行。

您正在寻找的是Thread.MemoryBarrier

但是,对于Microsoft当前的.NET实现,它们可能不是必需的。 有关详细信息, 请参阅此SO问题 。

在没有阅读有关.NET内存模型的任何内容的情况下,我可以向您保证.NET至少为您提供了这些保证(即锁定行为就像获取解锁一样),因为它们是最有用的最薄弱的保证。