Search code examples
c#multithreadingeventswaitwaitone

Event gets triggered after timeout is over


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.


Solution

  • 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.