编辑:我想问当两个线程在没有正确同步的情况下同时访问相同数据时会发生什么(在此编辑之前,该点没有被清楚地表示).
我有一个关于由C#编译器和JIT编译器执行的优化的问题.
考虑以下简化示例:
class Example { private Action _action; private void InvokeAction() { var local = this._action; if (local != null) { local(); } } }
在示例中,请忽略读取_action可能会产生缓存和过期的值,因为没有volatile说明符或任何其他同步.这不是点:)
编译器(或实际上是运行时的抖动)允许优化到局部变量的赋值,而是从内存中读取_action两次:
class Example { private Action _action; private void InvokeAction() { if (this._action != null) { this._action(); // might be set to null by an other thread. } } }
当字段_action通过并发分配设置为null时,可能会抛出NullReferenceException.
当然,在这个例子中,这样的“优化”将不会有任何意义,因为将值存储在寄存器中并因此使用局部变量将更快.但是在更复杂的情况下,有没有保证这样工作,如果没有重新读取记忆的价值?
解决方法
根据ECMA规范中定义的内存模型进行合法优化.如果_action是易失性的,内存模型将保证该值只读一次,因此此优化不会发生.
不过,我认为目前微软的CLR实现不会优化局部变量.