考虑轮询循环模式:
https://msdn.microsoft.com/en-us/magazine/jj883956.aspxprivate bool _flag = true;
public void Run()
{
// Set _flag to false on another thread
new Thread(() => { _flag = false; }).Start();
// Poll the _flag field until it is set to false
while (_flag) ;
// The loop might never terminate!
}
在这种情况下,.NET 4.5 JIT编译器可能会将循环重写为以下内容:if (_flag) { while (true); }
在单线程情况下,这种转换完全合法,通常将读取移出循环是一个很好的优化。但是,如果在另一个线程上将_flag设置为false,则优化会导致挂起。请注意,如果_flag字段是易失性的,则JIT编译器不会将读取移出循环。 (有关此模式的更详细说明,请参见12月文章中的“轮询循环”部分。)
如果我锁定_flag,JIT编译器是否仍会像上面显示的那样优化代码,还是仅使其易失性可以停止优化?
Eric Lippert对易失性有以下看法:
坦率地说,我建议您永远不要创建易失性字段。易失性字段意味着您正在做一些非常疯狂的事情:您正在尝试在两个不同的线程上读取和写入相同的值,而没有放置锁定。锁定保证在锁定内部读取或修改的内存被观察为一致,锁定保证只有一个线程同时访问给定的内存块等。需要使用锁定的情况非常少,因为您不了解确切的内存模型而不能正确编写代码的可能性非常大。除了最简单的Interlocked操作之外,我不尝试编写任何低锁代码。我将“易失性”使用给真正的专家。
总结一下:谁保证上述优化不会破坏我的代码?只有易失性吗?还是锁定语句?还是其他东西?
由于Eric Lippert不鼓励使用易失性,因此可能会有其他方法。一个布尔变量不是线程同步原语。这个问题是一个普遍的问题。编译器什么情况下不会进行优化?