Domanda

devo aspettare un evento per essere attivato. La mia soluzione iniziale era di uso AutoResetEvent e WaitOne(), ma l'evento è stato sempre ha attivato subito dopo il timeout attesa era finita. Così sono tornato al avvicinamento al di sotto, ma ho ancora lo stesso problema. 2 o 3 secondi dopo il timeout è finita l'evento viene attivato non importa quale sia il timeout è stato.

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

Ecco il codice del gestore eventi:

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

L'evento in sé viene attivato da un altro funzioni che chiama la funzione di cui sopra. In pratica sembra che questo:

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

Qualcuno ha idea di che cosa causa questo problema e come posso risolverlo?

EDIT: non è più rilevante. Inoltrato l'evento OnResponseArrived, perché ho trovato altra soluzione nel tempo.

È stato utile?

Soluzione

Thread.Join è una chiamata di blocco - si fermerà il filo si sta chiamando dal fare qualsiasi altro lavoro. La mia ipotesi è che si sta in attesa per l'evento su un thread in background, ma il codice che aumenterà il vostro evento è in esecuzione sullo stesso thread come il codice che viene eseguito in postato.

Chiamando thread.Join stai bloccando il filo che dovrebbe fare la vostra elaborazione. Quindi, si attende per il vostro timeout scada ... poi a seconda di quale metodo il codice Ripubblicato è in completa l'... poi il tuo trasformazione in realtà accade e l'evento ResponseArrived viene sollevata.

Sarebbe utile se si desidera inviare il resto del codice, ma il succo della soluzione sarà quella di eseguire il lavoro effettivo (qualunque sia il codice genera l'evento ResponseArrived) in un thread in background - e rimuovere la filettatura in più da il codice è pubblicato.

Modifica in risposta al commento ...

Al fine di sincronizzare i due pezzi di codice, è possibile utilizzare un AutoResetEvent. Invece di utilizzare Thread.Sleep e il vostro altro codice, provare qualcosa di simile:

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

Si noti che è necessario disporre della AutoResetEvent quando hai finito con esso.

Altri suggerimenti

Bene, la prima cosa che dovete fare è assicurarsi che DoStuff in realtà lavora in un thread in background.

Se questo è corretto, il modo in cui il codice è scritto in questo momento, non è necessario evento per generare un secondo filo, basta a farne una linea sotto, qualcosa di simile sarebbe semplicemente il lavoro (come 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);

Se questo funziona, e si sta programmando un'applicazione WinForms, allora si dovrebbe prendere in considerazione facendo il intero cosa in un thread in background, e quindi notificare l'utente quando è finito. Naturalmente, sarà necessario fornire maggiori dettagli, se hai bisogno di aiuto in questo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top