C#强制执行语句执行顺序
我的问题是关于C#中执行保证的顺序(大概是.Net)。我给出了一些Java示例,我知道一些可以比较的东西 对于Java(来自“实践中的Java并发”) 不能保证一个线程中的操作将按照程序给定的顺序执行,只要在该线程中无法检测到重新排序,即使重新排序对其他线程来说是明显的 那么代码呢C#强制执行语句执行顺序,c#,java,.net,multithreading,synchronization,C#,Java,.net,Multithreading,Synchronization,我的问题是关于C#中执行保证的顺序(大概是.Net)。我给出了一些Java示例,我知道一些可以比较的东西 对于Java(来自“实践中的Java并发”) 不能保证一个线程中的操作将按照程序给定的顺序执行,只要在该线程中无法检测到重新排序,即使重新排序对其他线程来说是明显的 那么代码呢 y = 10; x = 5; a = b + 10; 在分配y=10之前,可以实际分配a=b+10 和Java(来自同一本书) 当线程A启动由同一个锁保护的同步块时,它在同步块中或之前所做的一切对线程B
y = 10;
x = 5;
a = b + 10;
在分配y=10之前,可以实际分配a=b+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;
我特别感兴趣的是一个答案,它可以提供一个明确的参考或一些其他真正有意义的理由,因为像这样的保证很难测试,因为它们是关于编译器可以做什么的,不是它每次都做的,因为当它们失败时,当线程以错误的顺序命中对象时,你将很难重现间歇性错误。你要寻找的是
但是,它们对于Microsoft当前的.NET实现可能不是必需的。更多细节。我担心你会问这个问题,但既然你问了
y = 10;
Thread.MemoryBarrier();
x = 5;
Thread.MemoryBarrier();
a = b + 10;
Thread.MemoryBarrier();
// ...
从
按如下方式同步内存访问:执行当前线程的处理器不能以这样的方式重新排列指令:在调用MemoryBarrier之前的内存访问在调用MemoryBarrier之后的内存访问之后执行
,§10.10规定(我引述):
10.10执行顺序
执行过程应确保每个执行线程的副作用
保存在关键执行点。定义了副作用
作为对易失性字段的读取或写入,对非易失性变量的写入,
对外部资源的写入,以及引发异常。
这些副作用的顺序所处的关键执行点
应保留对易失性字段的引用(§17.4.3),
lock
语句(§15.12),以及线程创建和终止。
实现可以自由更改C#程序的执行顺序,
受以下限制:
- 数据依赖性保留在执行线程中。 也就是说,每个变量的值都是像所有语句一样计算的 在中,线程按原始程序顺序执行。(强调我的)
- 保留初始化顺序规则(§17.4.4、§17.4.5)
- 对于易失性读取,保留副作用的顺序 并写入(§17.4.3)。此外,一个实现不需要评估 表达式,如果它可以推断该表达式的值未被使用,并且 产生所需的副作用(包括调用方法或 访问易失性字段)。当程序执行被异步进程中断时 事件(例如由另一个线程引发的异常),不能保证 可观察到的副作用在原始程序顺序中是可见的
但是,如果您担心多线程问题,则需要深入研究标准并理解原子性规则。并非所有的操作都是原子操作。如果您是多线程的,并且调用的方法只引用局部变量(例如,实例或类(静态)成员),而不通过
lock
、互斥体、信号量或其他序列化技术序列化访问,您将自己置于竞争条件下。在没有阅读任何关于.NET内存模型的内容的情况下,我可以向您保证.NET至少会为您提供这些保证(即锁的行为类似于获取,解锁类似于释放),因为它们是最薄弱的有用保证。如果您有一个执行顺序重要的单元代码,您应该同步整个单元,而不是依赖编译器可能优化或可能不优化的内容。最终的资源是CLI规范,它指定了.net受约束的内存模型和执行模型。您对第二段代码的结论并不是从第二本书的引用中得出的。除非y x和a是易变的,否则线程内的操作顺序不会与其他线程中的内存可见性耦合。此外(至少在旧版本的java中),同步块不能保证这一点,因为它在进入同步块时只有内存障碍,而在离开时没有。因此,为什么java上的双重检查锁定被破坏了。我不知道这在更新的版本中是否发生了变化,就像我上次在2003年左右看到的那样。因此,要注意内存障碍在哪里,如果事情已经释放而不能获得语义。在C语言语言规范中有几点需要考虑,这里可以看到:具体地,请看第3.10、8.12和105.3节,可能还有其他一些。