2010-02-05 22 views
13

należy zablokować zdarzenie w następującym przypadku:powinienem zablokować "wydarzenie"?

event foo;

wątek A: wywoła foo + = handler;

wątek B: wywołaj foo - = handler;

Czy powinienem zablokować foo?

+1

Odpowiedź Jona jest dobra, ale zanim odpowiem, odpowiedziałabym, żeby zapytać, dlaczego chcesz zrobić zamek. * Jak myślisz, jaki problem masz i dlaczego blokowanie go rozwiązuje? * Mogę wymyślić wiele problemów, które możesz mieć w przypadku wydarzeń wielowątkowych; używałbyś różnych technik blokowania w zależności od problemu, który cię martwił. –

Odpowiedz

24

Zablokowanie na foo jest złym pomysłem, ponieważ wartość zmieni się za każdym razem. należy zablokować na zmienną, która nie zmiany:

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

pamiętać, że jeśli używasz zdarzenia polowych jak, na przykład:

public event EventHandler Foo; 

Pokochasz więc automatycznie uzyskać " lock (this) "przy dodawaniu/usuwaniu, chociaż musisz ręcznie dodać go podczas pobierania handler'a przed wywołaniem go (zakładając, że chcesz się upewnić, że przeczytałeś ostatnio zapisaną wartość). Osobiście nie jestem zwolennikiem blokowania "tego", ale możesz nie mieć nic przeciwko - i to z pewnością tworzy prostszy kod.

+0

@Jon, używam zdarzenia polowego, więc nie muszę blokować przy dodawaniu/usuwaniu, czy mam rację? – Benny

+0

@Jon, wywołuję procedurę obsługi zdarzenia bezpośrednio przy użyciu zdarzenia, np. Foo(), nie pobierając obsługi z wydarzenia, czy powinienem dodać blokadę? – Benny

+1

@Benny: Jeśli używasz zdarzenia polowego, nie musisz * dodawać/usuwać, aby się zablokować. Jeśli dzwonisz bezpośrednio do obsługi zdarzeń, w jaki sposób chronisz przed tym, że jest pusty? Zauważ, że nie możesz po prostu użyć 'if (foo! = Null) {foo (...); } 'as' foo' może * stać się * puste po teście. Ponadto nie gwarantowałoby to uzyskania najnowszej wartości - właśnie dlatego mam blokadę w mojej metodzie "OnFoo". (Modele pamięci potrafią robić zabawne rzeczy ...) –