Pregunta

Tengo que esperar a que se active un evento. Mi solución inicial era usar AutoResetEvent y WaitOne(), pero el evento fue siempre Activado justo después de que terminó el tiempo de espera de espera. Así que volví al enfoque a continuación, pero todavía tengo el mismo problema. 2 o 3 segundos después de que el tiempo de espera sobre el evento se active sin importar cuál fuera el tiempo de espera.

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

Aquí está el código del controlador de eventos:

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

El evento en sí se desencadena desde otras funciones que llama a la función anterior. Básicamente se ve así:

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

¿Alguien tiene una idea de qué causa este problema y cómo puedo resolverlo?

Editar: ya no es relevante. Reenvié el evento con protección contra respuestas, porque no encontré otra solución a tiempo.

¿Fue útil?

Solución

Thread.Join es una llamada de bloqueo: evitará que el hilo que esté llamando haga cualquier otro trabajo. Mi suposición es que eres esperando Para el evento en un hilo de fondo, pero el código que elevará su evento se ejecuta en el mismo hilo que el código que publica.

Llamando thread.Join Estás bloqueando el hilo que debería estar haciendo tu procesamiento. Entonces, espera que su tiempo de espera expire ... entonces sea cualquier método en el que se complete su código publicado ... después Tu procesamiento realmente ocurre y el ResponseArrived El evento se plantea.

Sería útil si publique el resto de su código, pero la esencia de la solución será ejecutar el trabajo real (cualquier código que plantee el ResponseArrived Evento) en un hilo de fondo, y elimine el roscado adicional del código que publicó.

EDITAR En respuesta al comentario ...

Para sincronizar sus dos piezas de código, puede usar un AutoResetEvent. En lugar de usar Thread.Sleep Y su otro código, intente algo como esto:

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

Tenga en cuenta que deberá deshacerse del AutoResetEvent Cuando hayas terminado con eso.

Otros consejos

Bueno, lo primero que debe hacer es asegurarse de que DoStuff en realidad funciona en un hilo de fondo.

Si eso es correcto, la forma en que se escribe su código en este momento, no necesita generar un segundo hilo, solo para unirlo a una línea a continuación, algo así simplemente funcionaría (como una prueba):

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

Si esto funciona y está programando una aplicación WinForms, entonces debería considerar hacer el completo cosa en un hilo de fondo, y luego notificando a la interfaz de usuario cuando esté terminado. Por supuesto, deberá proporcionar más detalles si necesita ayuda con eso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top