簡體   English   中英

EventWaitHandle 有時! 跳過線程

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM