C#强制执行语句的顺序

Joh*_*son 13 .net c# java multithreading synchronization

我的问题是关于C#中执行保证的顺序(大概是.Net).我给出了一些我知道要与之比较的Java示例.

对于Java(来自"Java Concurrency in Practice")

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

所以代码

  y = 10;
  x = 5;
  a = b + 10;
Run Code Online (Sandbox Code Playgroud)

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

在Java中(来自同一本书)

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

所以在Java中

 y = 10;
 synchronized(lockObject) {
     x = 5;
 }
 a = b + 10;
Run Code Online (Sandbox Code Playgroud)

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

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

 y = 10;
 lock(lockObject) {
     x = 5;
 }
 a = b + 10;
Run Code Online (Sandbox Code Playgroud)

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

Nic*_*rey 6

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

10.10执行顺序 执行应继续执行,以便在关键执行点保留每个执行线程的副作用.甲副作用被定义为挥发性字段的读或写,以非易失性可变的写入,到外部资源的写入,和一个异常的投掷.应保留这些副作用的顺序的关键执行点是对volatile字段(第17.4.3节), 语句(第15.12节)以及线程创建和终止的引用lock .实现可以自由更改C#程序的执行顺序,但受以下约束:

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

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

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

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

但是如果你担心多线程问题,你需要深入研究标准并理解关于原子性的规则.并非每项操作都必须是原子的.如果您是多线程并且调用引用除局部变量(例如,实例或类(静态)成员之外的任何东西)的方法而没有通过lock,互斥体,信号量或其他序列化技术进行序列化访问,那么您将自己开放参加比赛条件.


Kry*_*pes 5

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

y = 10;
Thread.MemoryBarrier();
x = 5;
Thread.MemoryBarrier();
a = b + 10;
Thread.MemoryBarrier();
// ...
Run Code Online (Sandbox Code Playgroud)

来自msdn

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