2011-01-06 20 views
6

Czy ta metoda rozszerzenia jest bezpieczna?Czy metoda rozszerzenia jest bezpieczna?

public static class Extensions 
    { 
     public static void Raise<T>(this EventHandler<T> handler, 
     object sender, T args) where T : EventArgs 
     { 
     if (handler != null) handler(sender, args); 
     } 
    } 

Czy muszę to zmienić?

public static class Extensions 
    { 
     public static void Raise<T>(this EventHandler<T> handler, 
     object sender, T args) where T : EventArgs 
     { 
     var h = handler; 
     if (h!= null) h(sender, args); 
     } 
    } 
+0

szczegóły dotyczące projektowania i wdrażania zdarzeń dotyczących wątków http://stackoverflow.com/questions/786383/c-events-and-thread-safety – user44298

Odpowiedz

9

Znalazłeś interesującą pętlę, która potknęła wszystkich. Nie, to nie jest bezpieczne dla wątków.

Chociaż jest to wygląda podobnie jak EventHandler <> odwołanie jest kopiowane za pośrednictwem argumentu method, to nie jest to, co dzieje się w czasie wykonywania. Metody rozszerzeń mogą podlegać inkrementacji, podobnie jak w przypadku zwykłej metody instancji. W rzeczywistości jest bardzo prawdopodobne, że zostanie zaindeksowane, ponieważ jest tak małe. Nie ma kopii, sam musisz ją wykonać.

+1

Nie jestem pewien, że masz rację. Miałoby to zastosowanie tylko wtedy, gdy wywołująca funkcja wywoływała metodę na wartości, która mogłaby zostać zmieniona przez inny wątek (pole klasy na przykład zamiast zmiennej lokalnej). Nie wiem, czy JIT zainicjowałby takie zaproszenie w tej sprawie. – tster

+0

Jest to jednak bardzo ciekawy temat. Żałuję, że nie byłem w pracy i miałem czas, aby zagłębić się w to jeszcze bardziej. – tster

+1

Cóż, na tym polega właśnie test zerowy w kodzie podnoszącym zdarzenia. –

7

Żadna z wersji nie jest bezpieczna dla wątków, w zależności od tego, co rozumie się przez "Threadafe". Zastanów się nad drugą wersją:

var h = handler;   
    if (h!= null) 
     h(sender, args); 

"handler" to kopia pola, które ma w sobie niezmiennego delegata. Załóżmy, że pole zostało zmutowane do "null" w innym wątku po sprawdzeniu zerowym. Twój kod nie ulega awarii w tym przypadku, ponieważ wykonałeś kopię oryginalnej wartości niezerowej. Lecz tylko nie rozbicie się na nie powoduje, że program jest bezpieczny. Program, który nie ulega awarii, ale nadal generuje złe wyniki, nadal nie jest bezpieczny dla wątków.

Załóżmy, że gdy drugi wątek ustawił wartość pola zdarzenia na wartość null, zmutowano także stan, w którym poprzednia zawartość wymagała poprawnego działania. Teraz uruchomisz program obsługi zdarzeń, który zależy od stanu, który został zmutowany w innym wątku; używasz obsługi zdarzeń przestarzały.

Nie ma łatwego sposobu ochrony przed tym problemem; jeśli to jest sytuacja, w której się znajdujesz, będziesz musiał zaprojektować swoją logikę gwintowania bardzo ostrożnie, aby poradzić sobie z sytuacją.

Powiązane problemy