Событие запускается после истечения времени ожидания - PullRequest
0 голосов
/ 27 января 2011

Мне нужно дождаться события, которое будет запущено.Моим первоначальным решением было использовать AutoResetEvent и WaitOne(), но событие всегда вызывалось сразу после истечения времени ожидания.Итак, я вернулся к подходу ниже, но у меня все еще есть та же проблема.Через 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 ]

2 голосов
/ 27 января 2011

Ну, первое, что вам нужно сделать, это убедиться, что 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, тогдавам следует подумать о том, чтобы сделать весь в фоновом потоке, а затем уведомить пользовательский интерфейс о его завершении.Конечно, вам потребуется предоставить более подробную информацию, если вам нужна помощь в этом.

2 голосов
/ 27 января 2011

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, когда вы закончите с ним.

...