2011-01-27 72 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。当然,如果你需要帮助,你需要提供更多的细节。

相关问题