2011-01-27 112 views
0

我必須等待事件被觸發。我最初的解決方案是使用AutoResetEventWaitOne(),但事件是總是在等待超時結束後觸發。所以我回到了下面的方法,但我仍然有同樣的問題。超時結束後2或3秒,無論超時是什麼,事件都會被觸發。超時結束後觸發事件

_wait = true; 
_delayedResponse = null; 

var thread = new Thread(delegate 
{ 
     while (_wait) 
     { 
      Thread.Sleep(500); 
      if (_delayedResponse != null) 
       return; 
     } 
}); 

thread.Start(); 
var received = thread.Join(_responseTimeout); 
_wait = false; 

if (!received) 
    throw new TimeoutException(
     "Timeout for waiting for response reached."); 

return _delayedResponse; 

這裏是事件處理代碼:

private void OnResponseArrived(object sender, ResponseEventArgs args) 
{ 
    _delayedResponse = args.VerificationResponse; 
} 

事件本身是由調用上述功能的其他功能觸發。 基本上它看起來是這樣的:

var result = DoStuff(); // Library function that is responsible for the event 
if (result.Status == Status.Wait) 
    Wait(); // Function above 

有沒有人有一個想法是什麼原因導致這個問題,我該如何解決呢?

編輯:不再相關。轉發了OnResponseArrived事件,因爲我沒有及時發現其他解決方案。

+2

你從哪裏觸發事件? – 2011-01-27 12:35:59

+0

什麼意思是「事件被觸發,無論超時是什麼」? `ResponseArrived`事件?你確定這個事件是從另一個線程發起的嗎? – Groo 2011-01-27 12:39:32

+0

謝謝你的評論。我更新了這個問題。 – xsl 2011-01-27 12:39:38

回答

2

Thread.Join是一個阻止呼叫 - 它會阻止您從其他任何工作中呼叫的線程。我的猜測是,你等待用於在後臺線程的事件,但會提高你的事件中的代碼作爲你的代碼貼出運行在同一個線程上運行。

通過調用thread.Join你阻止應該進行處理的線程。所以,你等待你的超時過期...然後無論你的發佈代碼是在哪裏完成... 然後你的處理實際上發生和ResponseArrived事件引發。

如果您發佈代碼的其餘部分,但解決方案的要點是在後臺線程中運行實際工作(無論代碼如何提高ResponseArrived事件),並且刪除額外的線程從你發佈的代碼。

編輯響應評論...

爲了同步兩段代碼,你可以使用一個AutoResetEvent。而不是使用Thread.Sleep和你的其他代碼,嘗試這樣的事情:

// create an un-signalled AutoResetEvent 
AutoResetEvent _waitForResponse = new AutoResetEvent(false); 

void YourNewWorkerMethod() 
{ 
    _delayedResponse = null; 
    var result = DoStuff(); 

    // this causes the current thread to wait for the AutoResetEvent to be signalled 
    // ... the parameter is a timeout value in milliseconds 
    if (!_waitForResponse.WaitOne(5000)) 
     throw new TimeOutException(); 

    return _delayedResponse; 
} 


private void OnResponseArrived(object sender, ResponseEventArgs args) 
{ 
    _delayedResponse = args.VerificationResponse; 
    _waitForResponse.Set(); // this signals the waiting thread to continue... 
} 

注意,您需要處置AutoResetEvent的,當你用它做。

2

那麼,你需要做的第一件事就是確保DoStuff實際上在後臺線程中工作。

如果這是正確的,那麼現在編寫代碼的方式,你不需要產生第二個線程,只需要將它加入下面一行,就可以簡單地工作(作爲測試):

// handler needs to be attached before starting 
library.ResponseReceived += OnResponseReceived; 

// call the method 
var result = library.DoStuff(); 

// poll and sleep, but 10 times max (5s) 
int watchdog = 10; 
while (_delayedResponse == null && watchdog-- > 0) 
    Thread.Sleep(500); 

// detach handler - always clean up after yourself 
library.ResponseReceived -= OnResponseReceived; 

Console.WriteLine(_delayedResponse != null); 

如果一切正常,並且您正在編寫的WinForms應用程序,那麼你應該考慮這樣做在後臺線程的整個的事情,然後當它完成通知UI。當然,如果你需要幫助,你需要提供更多的細節。

相關問題