我想大多数人都知道了以下问题在Release模式建设(从Threading in C#采取代码)时发生的:挥发性古怪
static void Main()
{
bool complete = false;
var t = new Thread (() =>
{
bool toggle = false;
while (!complete) toggle = !toggle;
});
t.Start();
Thread.Sleep (1000);
complete = true;
t.Join(); // Blocks indefinitely
}
由于编译器优化缓存的complete
的价值,从而防止孩子线程从不断看到更新的值。
然而,改变上面的代码位:
class Wrapper
{
public bool Complete { get; set; }
}
class Test
{
Wrapper wrapper = new Wrapper();
static void Main()
{
var test = new Test();
var t = new Thread(() =>
{
bool toggle = false;
while (!test.wrapper.Complete) toggle = !toggle;
});
t.Start();
Thread.Sleep(1000);
test.wrapper.Complete = true;
t.Join(); // Blocks indefinitely
}
}
使问题消失(即子线程能够在1秒后退出),而不使用volatile
,内存栅栏,或任何其他引入隐式栅栏的机制。
完成标志的添加封装如何影响其在线程之间的可见性?
您的代码不能保证能正常工作,但也不能保证失败。您不应该依赖编译器优化来实现正确性(或者在这种情况下不正确)。 – svick
@svick:我其实不是。这只是我不小心注意到的事情。 – Tudor
[可重复使用的挥发性使用示例]的可能重复(http://stackoverflow.com/questions/6164466/a-reproducable-example-of-volatile-usage) –