我覺得我應該知道這個答案,但無論如何我會問,以防萬一我犯了一個潛在的災難性錯誤。是否安全地發出信號並立即關閉ManualResetEvent?
下面的代碼按預期執行沒有錯誤/異常:
static void Main(string[] args)
{
ManualResetEvent flag = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(s =>
{
flag.WaitOne();
Console.WriteLine("Work Item 1 Executed");
});
ThreadPool.QueueUserWorkItem(s =>
{
flag.WaitOne();
Console.WriteLine("Work Item 2 Executed");
});
Thread.Sleep(1000);
flag.Set();
flag.Close();
Console.WriteLine("Finished");
}
當然,如通常與多線程代碼的情況下,一個成功的試驗並不能證明這實際上是線程安全的。如果我在Set
之前放置Close
,即使文檔明確指出嘗試在Close
之後執行任何操作會導致未定義的行爲,該測試也會成功。
我的問題是,當我調用ManualResetEvent.Set
方法,是保證信號所有等待線程控制權返回給調用者之前?換句話說,假設我能夠保證不會有進一步的呼叫WaitOne
,在這裏關閉句柄是否安全,還是有可能在某些情況下,這些代碼會阻止一些服務員收到信號或結果在ObjectDisposedException
?
文檔只說Set
把它放在一個「信號狀態」 - 它似乎並沒有做出什麼時候服務員會真正得到該信號的任何索賠,所以我想是肯定的。
一個有趣的實驗是在WaitOne()之前發生Sleep。這將允許您測試WaitOne()在'flag'爲Close()'時執行的操作。 – 2010-02-25 19:16:37
@Phillip Ngan:正如文檔所述,它實際上並沒有定義。如果你在'Thread.Sleep'之前的代碼中移動'Close','WaitOne'期間會出現'ObjectDisposedException'(「Safe handle has been closed」)。另一方面,如果直接在'Thread.Sleep'後面移動'Close',兩個線程都會發出信號並且成功執行。所以,未定義的行爲,在「壞」代碼中存在爭用條件。我只想確保在我認爲是我的「好」代碼中沒有類似的未定義行爲。 :) – Aaronaught 2010-02-25 19:20:54