Event gets triggered after timeout is over

3.3k views Asked by At

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.

2

There are 2 answers

1
Dan Puzey On BEST ANSWER

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.

1
vgru On

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.