我对 C#/.NET 中的合法指令重新排序有疑问。
让我们从这个例子开始。我们在某个类中定义了这个方法,其中 _a、_b 和 _c 是字段。
int _a;
int _b;
int _c;
void Foo()
{
_a = 1; // Write 1
_b = 1; // Write 2
_c = 1; // Write 3
}
我们的调用环境看起来像这样。
//memory operations
ClassInstance.Foo();
//memory operations
我想知道当这个方法调用被内联而不是函数调用时,什么样的合法指令重新排序是可能的。更具体地说,我想知道在 Foo() 中重新排序内存操作是否/何时是合法的,而内存操作在它之外(来 self 们之前的示例,//内存操作)。
此外,函数调用(无内联)在某种意义上“产生内存障碍”。就像在函数调用之前或之后发生的内存操作一样,无法使用函数调用内的内存操作重新排序。
如果是这样,当它被编译器内联时,它是否仍然具有这种“内存屏障”行为?
最佳答案
C# Language Specification可以帮助回答这个问题。关于执行顺序的部分是这样说的:
3.10 Execution order
Execution of a C# program proceeds such that the side effects of each executing thread are preserved at critical execution points. ....The execution environment 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.
Initialization ordering rules are preserved (§10.5.4 and §10.5.5).
The ordering of side effects is preserved with respect to volatile reads and writes (§10.5.3).
(我遗漏了更多内容;该规范可读性很强,所以如果您真的想深入了解细节,我建议您看一看)。
从本质上讲,规则可以被认为是“抖动可能会重新安排执行顺序,只要执行线程无法观察到差异”。但是,其他 线程可能会观察到差异。在 post by Eric Lippert on the Coverity blog ,他说:
...the CPU may as an optimization choose to [rearrange execution order] provided that doing so is not detectable by the current thread. But that fact could be observed by another thread...
因此,如果操作顺序对其他线程和当前线程都很重要,那么您需要创建一个“关键执行点”;最简单的方法可能是用锁包围语句。
关于c# - 指令重新排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22420368/