[英]EventWaitHandle sometimes! skip thread
我使用的是 VS 2012,.Net 4.5。
執行此代碼(只需升級有關線程的文章中的一些示例):
using System.Threading;
class BasicWaitHandle
{
static EventWaitHandle wh = new AutoResetEvent(false);
static void Main()
{
new Thread(Waiter).Start();
new Thread(Waiter).Start();
Thread.Sleep(1000); // Подождать некоторое время...
wh.Set(); // OK – можно разбудить
wh.Set();
Console.ReadLine();
}
static void Waiter()
{
Console.WriteLine("Avait..."+Thread.CurrentThread.ManagedThreadId);
wh.WaitOne(); // Ожидать сигнала
Console.WriteLine("Got a signal"+Thread.CurrentThread.ManagedThreadId);
}
}
我調試了幾次,但通常(並非總是)得到錯誤的結果。 起初(一次或多次)它是正確的:
Avait...10
Avait...11
Got a signal 11
Got a signal 10
但隨后它就開始跳過一個線程(先是某個線程?然后是某個線程):
Avait...10
Avait...11
Got a signal 11 (or 10)
而程序只是沒有反應。 幾分鍾后,它給出了一些正確的結果,但隨后又出錯了……
此外,當我逐步調試它時,它總是正確運行。
那么,也許我應該選擇另一種方法? 但這看起來像我所期望的,即使線程以隨機順序收到信號......
我很不確定你可以對多個awaters使用相同的AutoResetEvent
,因為Set
不等待第一個線程完成它的Wait
:
不能保證每次調用 Set 方法都會從重置模式為 EventResetMode.AutoReset 的 EventWaitHandle 中釋放線程。 如果兩個調用靠得太近,以至於第二個調用發生在一個線程被釋放之前,那么只有一個線程被釋放。 就好像第二次通話沒有發生一樣。 此外,如果在沒有線程等待且 EventWaitHandle 已發出信號時調用 Set,則調用無效。
我會在設置信號期間使用ManualResetEvent
和同步(以確保哪個等待線程接收信號)或(更好)為每個等待函數使用專用事件(每個線程都會以自己的事件開始等待,您將需要某種這些線程的管理器來創建等待事件並讓Set
方法來發出所有這些事件的信號)。
ps:順便說一句,可以用俄語重復上面說的^^
兩個線程都啟動並運行,直到它們在 WaitHandle 上阻塞。 當WaitHandle 被設置時,一個線程將被喚醒並且事件將被重置。
您無法保證哪個線程會被喚醒,因此無法確保順序。 正確運行時,每次都會喚醒 10 或 11,然后是另一個。
在您的應用程序掛起的情況下,問題在於執行順序。 主線程在第一個線程喚醒之前執行對 Event.Set() 的兩個調用。 AutoResetEvent 不是計數器,它要么被設置,要么被取消,所以第二次調用 Set() 會丟失。
如果在調用 Set() 之間使用 Sleep(),您將讓步給其他線程,並給其中一個線程喚醒和重置事件的時間。
在它正常工作的情況下,你很幸運,等待的線程有機會在調用 Set() 之間運行。 這稱為競爭條件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.