我觉得大多数人都知道下面这个问题,在 Release 模式下构建时会发生(代码来自于 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
}
}
不使用volatile
、内存屏障或任何引入隐式屏障的机制,即可解决问题(即子线程能够在1秒后退出)。
添加完成标志的封装如何影响线程之间的可见性?