我想大多數人都知道了以下問題在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) –