2014-01-13 37 views
1

我使用VS 2012,.Net 4.5。有時會有EventWaitHandle!跳過線程

執行該代碼(剛剛從文章更新一些樣品約線程):

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 

但隨後纔開始跳過一個線程(somethimes第一somethimes第二?):

Avait...10 
Avait...11 
Got a signal 11 (or 10) 

和節目只是沒有反應。在幾分鐘內它會給出一些正確的結果,但然後再出錯...

此外,當我調試它一步一步它總是正確行事。

那麼,也許我應該選擇另一種方法?但是,這看起來像我所期待的,即使有線程以隨機順序信號...

回答

1

我非常不確定,你可以使用相同的AutoResetEvent多個awaters,因爲Set不是等待第一個線程來完成其Wait

無法保證每次調用Set方法都會從其重置模式爲EventResetMode.AutoReset的EventWaitHandle釋放一個線程。如果兩個調用靠得太近,那麼第二個調用在一個線程被釋放之前發生,只有一個線程被釋放。就好像第二個電話沒有發生。另外,如果在沒有線程在等待並且已經發送了EventWaitHandle的情況下調用Set,則該調用不起作用。

我與ManualResetEvent和同步去設定信號時(保證,什麼等待的線程接收信號)或(更好)使用專用事件每個等待功能(每個線程將與它自己的事件開始等待,你將需要那些線程的經理來創建等待事件,並有Set方法什麼會告知所有這些事件)。

P.S:可以在上面用俄語說地重複順便說一句^^

+0

很確定你是對的。我在wh.Set()之間添加Thread.Sleep(1000) - 調用和錯誤不重複。 ДочитаюАлбахари,тогдаподберуболееудачныйвариант。 – user3190541

0

兩個線程啓動和運行,直到他們對WaitHandle的阻塞。當WaitHandle被設置時,一個線程將被喚醒並且事件將被重置。

您無法保證哪個線程會被喚醒,所以訂單無法保證。當正確運行時,每次10或11會醒來,然後是另一次。

在應用程序掛起的情況下,問題是執行順序。主線程在第一個線程喚醒之前執行對Event.Set()的兩個調用。 AutoResetEvent不是一個計數器,它可以是set或unset,所以第二次調用Set()會丟失。

如果您在調用Set()之間調用Sleep(),您將屈服於其他線程,並讓其中一個時間喚醒並重置事件。

在正常工作的情況下,您會很幸運,等待的線程有機會在對Set()的調用之間運行。這被稱爲競賽條件。