超时结束后触发事件

发布于 2024-10-14 17:06:00 字数 1088 浏览 7 评论 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事件,因为我没有及时找到其他解决方案。

I have to wait for an event to be triggered. My initial solution was to use AutoResetEvent and WaitOne(), but the event was always triggered just after the waiting timeout was over. So I went back to the approach below, but I still have the same problem. 2 or 3 seconds after the timeout is over the event gets triggered no matter what the timeout was.

_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;

Here is the event handler code:

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

The event itself is triggered from another functions that calls the function above.
Basically it looks like this:

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

Does anyone have an idea what causes this problem and how I can solve it?

EDIT: No longer relevant. Forwarded the OnResponseArrived event, because I found no other solution in time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浪菊怪哟 2024-10-21 17:06:00

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 后,您需要将其释放。

Thread.Join is a blocking call - it'll stop the thread you're calling from doing any other work. My guess is that you're waiting for the event on a background thread, but the code that will raise your event is running on the same thread as the code you posted runs in.

By calling thread.Join you're blocking the thread that should be doing your processing. So, you wait for your timeout to expire... then whichever method your posted code is in completes... then your processing actually happens and the ResponseArrived event is raised.

It would be useful if you'd post the rest of your code, but the gist of the solution will be to run the actual work (whatever code raises the ResponseArrived event) in a background thread - and remove the extra threading from the code you posted.

EDIT in response to comment...

In order to synchronise your two pieces of code, you can use an AutoResetEvent. Instead of using Thread.Sleep and your other code, try something like this:

// 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...
}

Note that you'll need to dispose of the AutoResetEvent when you're done with it.

知足的幸福 2024-10-21 17:06:00

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

Well, the first thing you need to do is make sure that DoStuff actually works in a background thread.

If that is correct, the way your code is written right now, you don't event need to spawn a second thread, just to join it one line below, something like this would simply work (as a test):

// 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);

If this works, and you are programming a WinForms app, then you should consider doing the entire thing in a background thread, and then notifying the UI when it's finished. Of course, you will need to provide more details if you need help with that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文