2010-02-05 13 views
13

dovrei bloccare l'evento nel seguente caso:devo bloccare "evento"?

evento foo;

thread A: chiamerà foo + = gestore;

thread B: chiamerà foo - = handler;

devo bloccare?

+1

La risposta di Jon è buona, ma prima di rispondere, spingevo indietro per chiedere perché si desidera bloccare la serratura. * Quale problema credi di avere, e perché credi che il blocco lo risolva? * Posso pensare a più problemi che potresti avere intorno agli eventi multithreaded; useresti diverse tecniche di blocco a seconda del problema che ti preoccupava. –

risposta

24

Blocco su foo è una cattiva idea, perché il valore cambierà ogni volta. Si dovrebbe chiudere su una variabile che non lo fa cambiamento:

private readonly object eventLock = new object(); 
private EventHandler fooHandler; 

public event EventHandler Foo 
{ 
    add 
    { 
     lock (eventLock) 
     { 
      fooHandler += value; 
     } 
    } 
    remove 
    { 
     lock (eventLock) 
     { 
      fooHandler -= value; 
     } 
    } 
} 

private void OnFoo(EventArgs e) 
{ 
    EventHandler handler; 
    lock (eventLock) 
    { 
     handler = fooHandler; 
    } 
    if (handler != null) 
    { 
     handler(this, e); 
    } 
} 

Si noti che se si utilizza un evento di campo simile, in questo modo:

public event EventHandler Foo; 

allora si otterrà automaticamente un " lock (this) "su aggiungi/rimuovi, anche se dovresti aggiungerlo manualmente durante il recupero del gestore prima di chiamarlo (supponendo che tu voglia assicurarti di leggere il valore scritto più di recente). Personalmente non sono un fan del lock su "this", ma non ti dispiacerà, e certamente rende il codice più semplice.

+0

@Jon, sto usando un evento simile a un campo, quindi non ho bisogno di bloccare l'aggiunta/rimozione, sto bene? – Benny

+0

@Jon, sto chiamando il gestore di eventi usando direttamente l'evento, come questo foo(), non recuperando il gestore dall'evento, dovrei aggiungere il blocco? – Benny

+1

@Benny: se stai usando un evento di tipo campo non hai * un * aggiungi/rimuovi per bloccare. Se stai chiamando direttamente il gestore di eventi, come stai evitando che sia nullo? Nota che non puoi semplicemente usare 'if (foo! = Null) {foo (...); } 'as' foo' potrebbe * diventare * null dopo il test. Inoltre, non garantirebbe il valore più recente - ecco perché ho il blocco nel mio metodo 'OnFoo'. (I modelli di memoria possono fare cose divertenti ...) –