C#强制执行语句的顺序 [英] C# enforcing order of statement execution

查看:162
本文介绍了C#强制执行语句的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



For Java(来自Java Concurrency in Practice)


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


所以代码

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

实际上可以分配a = b + 10在分配y = 10之前



在Java中(来自同一本书)


线程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执行顺序
执行应继续进行,以便在关键执行点保留每个执行线程
的副作用。
副作用定义为
作为易失性字段的读取或写入,写入非易失性变量,
a写入外部资源,以及抛出例外。
应保留这些副作用
的顺序的关键执行点是对volatile字段的引用(第17.4.3节),

lock 语句(第15.12节),以及线程创建和终止。
实现可以自由更改C#程序的执行顺序,
受以下限制:




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

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



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





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


My question is about order of execution guarantees in C# (and presumably .Net in general). I give Java examples I know something about to compare with.

For Java (from "Java Concurrency in Practice")

There is no guarantee that operations in one thread will be performed in the order given by the program, as long as the reordering is not detectable from within that thread-even if the reordering is apparent to other threads.

So the code

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

may actually assign a=b+10 Before assigning y = 10

And in Java (from the same book)

Everything thread A does in or prior to a synchronized block is visible to thread B when it starts a synchronized block guarded by the same lock.

so in Java

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

y = 10 and x = 5 are guaranteed to both run before a = b + 10 (I don't know whether y = 10 is guaranteed to run before x = 5).

What guarantees does C# code make for the order of execution for the C# statements

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

I am particularly interested in an answer that can provide a definitive reference or some other really meaningful justification as guarantees like this are hard to test because they are about what the compiler is allowed to do, not what it does every time and because when they fail you are going to have very hard to reproduce intermittent bugs when threads hit things in just the wrong order.

解决方案

ISO 23270:2006 — Information technology—Programming languages—C#, §10.10 says (and I quote):

10.10 Execution order Execution shall proceed such that the side effects of each executing thread are preserved at critical execution points. A side effect is defined as a read or write of a volatile field, a write to a non-volatile variable, a write to an external resource, and the throwing of an exception. The critical execution points at which the order of these side effects shall be preserved are references to volatile fields (§17.4.3), lock statements (§15.12), and thread creation and termination. An implementation is free to change the order of execution of a C# program, subject to the following constraints:

  • Data dependence is preserved within a thread of execution. That is, the value of each variable is computed as if all statements in the thread were executed in original program order. (emphasis mine).

  • Initialization ordering rules are preserved (§17.4.4, §17.4.5).

  • The ordering of side effects is preserved with respect to volatile reads and writes (§17.4.3). Additionally, an implementation need not evaluate part of an expression if it can deduce that that expression’s value is not used and that no needed side effects are produced (including any caused by calling a method or accessing a volatile field). When program execution is interrupted by an asynchronous event (such as an exception thrown by another thread), it is not guaranteed that the observable side effects are visible in the original program order.

The other CLI standards are likewise available gratis from the ISO at

But if you are worried about multi-threading issues, you'll need to dig deeper into the standards and understand the rules about atomicity. Not every operation is warranted to be atomic. If you are multi-threaded and invoking methods that reference anything but local variables (e.g., instance or class (static) members) without serializing access via lock, a mutex, a semaphore, or some other serialization technique, you are leaving yourself open to race conditions.

这篇关于C#强制执行语句的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆