2012-01-25 11 views
11

Ho il seguente modello di progettazione:Come verificare se ManualResetEvent è stato eliminato, quando si tenta di impostare() all'interno di un EventHandler?

var myObjectWithEvents = new ObjectWithEvents(); 
    using (var mre = new ManualResetEvent(false)) { 
     var onEvent = new EventHandler<EventArgs>((sender, e) => { mre.Set(); }); 
     try { 
      myObjectWithEvents.OnEvent += onEvent; 
      var task = Task.Factory.StartNew(() => { 
       myObjectWithEvents.DoSomethingThatShouldRaiseAnEvent(); 
      }); 
      var timedOut = !mre.WaitOne(10000); 
     } 
     finally { 
      myObjectWithEvents.OnEvent -= onEvent; 
     } 
    } 

Il mio problema è che se OnEvent viene generato dopo le WaitOne volte su e fasi di esecuzione fuori del blocco utilizzando, il gestore onEvent evento locale sarà comunque chiamato e cercare di impostare ManualResetEvent mre che sarà già stato eliminato, anche se onEvent avrebbe dovuto essere registrato da OnEvent.

Una soluzione semplice sarebbe quello di verificare se mre è già stato smaltito, ma purtroppo non c'è tale campo, e credo che il confezionamento mre.Set() all'interno di un blocco try catch per ignorare l'eccezione non è pulito dato che l'eccezione potrebbe verificarsi abbastanza frequentemente.

Che cosa suggeriresti come il modo migliore e più semplice per raggiungere lo scopo del modello di codice sopra (vale a dire in attesa di un evento da sollevare) senza incorrere in questo tipo di problema?

Edit: grazie alle vostre risposte, ho creato la seguente estensione e sostituito mre.Set() con mre.TrySet():

public static void TrySet(this ManualResetEvent mre) { 
     if (!mre.SafeWaitHandle.IsClosed) mre.Set(); 
    } 
+0

Potrebbe fornire maggiori dettagli sui requisiti dell'applicazione? Chiedete "il modo migliore e più semplice per raggiungere lo scopo del suddetto modello di codice", ma questo ci lascia indovinare quali sono le vostre esigenze basate sul vostro codice corrente. – Justin

+0

Causa problemi durante l'esecuzione di Set() su MRE eliminato? – sll

+0

Sì mre.Set() su Mre disposed genererà un'eccezione ... –

risposta

7

Si può cercare di controllarlo dalla struttura mre.SafeWaitHandle.IsClosed

9
ManualResetEvent.SafeWaitHandle.IsClosed 

sembra strano, ma l'unica cosa che la dispose fa è per chiudere la safeHandler , che è l'unico oggetto a cui è destinato il dispositivo ...

Il Dispose di SafeWaitHandle, modifica questa proprietà da False a True.

+0

+1 dal momento che sei il primo a suggerire la bandiera di 'IsClosed' – sll

+0

Grazie a ssl! gradito –

1

Come caso provare utilizzando semplici interruttore booleano che indica se l'impostazione ManualResetEvent è reale:

bool isMreSync = true; 
var myObjectWithEvents = new ObjectWithEvents(); 
using (var mre = new ManualResetEvent(false)) 
{ 
    var onEvent = new EventHandler<EventArgs>((sender, e) => 
       { 
        if (isMreSync) 
        { 
         mre.Set(); 
        } 
       }); 

    // try ... finally block 
} 

isMreSync = false; 

Se l'evento potrebbe essere eseguito in modo asincrono - sincronizza l'accesso allo switch booleano.

Problemi correlati