我必须等待触发事件。我最初的解决方案是使用 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

有人知道是什么原因导致了这个问题,以及如何解决问题?

编辑:不再相关。转发了OnRreresponserrived事件,因为我没有及时找到其他解决方案。

有帮助吗?

解决方案

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 完成后。

其他提示

好吧,您需要做的第一件事是确保 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。当然,如果您需要帮助,您将需要提供更多详细信息。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top