2013-08-29 16 views
5

Używam aplikacji, która synchronizuje wątki za pomocą ManualResetEvent. FxCop kazał mi wyrzucić te przedmioty. Znalazłem następującą dyskusję, która powiedziała mi to samo:Kiedy należy zdemontować ManualResetEvent?

Do I need to Dispose() or Close() an EventWaitHandle?

Ale nie wiem kiedy do dysponowania instancję ManualResetEvent.

Następujący kod uproszczony pokazuje problem:

private void btn_Click(object sender, EventArgs e) 
{ 
    var mre = new ManualResetEvent(false); 
    new Thread(() => this.SetEvent(mre)).Start(); 
    for (int i = 0; i < 10; ++i) 
    { 
     new Thread(() => this.WaitFor(mre)).Start(); 
    } 
} 

private void SetEvent(ManualResetEvent manualResetEvent) 
{ 
    Thread.Sleep(10000); 
    manualResetEvent.Set(); 
} 

private void WaitFor(ManualResetEvent manualResetEvent) 
{ 
    manualResetEvent.WaitOne(); 
} 

Problemem jest to, że wiele instancji ManualResetEvent istnieć i wielu wątków czeka na każdym przypadku.

Jeśli zapamiętuję instancje na liście, nie wiem, kiedy je zutylizować. Pozbycie się go po wywołaniu WaitOne() wywoła je kilka razy i być może zostanie usunięte, podczas gdy inne wątki wciąż czekają.

Wątek, który utworzył wydarzenie, nie ma żadnego odniesienia do niego. Wątek setera nie powinien go usuwać, ponieważ na MRE czekają inne wątki. Każdy wątek oczekujący nie jest w stanie go usunąć, jak wspomniano wcześniej.

Pytanie brzmi: Kiedy należy usunąć ten podręcznik ManualResetEvent?

+1

Kod jest bezsensowny i jest tylko * jeden * wystąpienie MRE. Pozbycie go na końcu metody jest w porządku. –

+1

Nie, nie sądzę.Kod tworzący MRE to obsługa zdarzeń click button. Możesz go wielokrotnie kliknąć, tworząc wiele MRE. Powyższy kod jest uproszczony. Usunięcie MRE na końcu tej metody nie będzie działać, ponieważ istnieje 11 wątków, które używają tego MRE po zakończeniu metody. Wątek ustawiający czeka 10 sekund, a 10 innych wątków czeka na to MRE. –

Odpowiedz

5

Urządzenie ManualResetEvent należy wyrzucić, gdy już go nie potrzebujesz. Twoje prawdziwe pytanie brzmi: "skąd mam wiedzieć, że już go nie potrzebuję?"

Zazwyczaj coś jest powiadamiane, gdy wątki są zrobione, i wywołujesz Join w wątku. Lub wątek ustawia pewne zdarzenie, aby wskazać, że zostało zakończone. Jeśli masz wiele wątków, wszystkie mogą sygnalizować CountdownEvent. Istnieje kilka innych sposobów zarządzania powiadomieniami o wątkach.

Chodzi o to, że jeśli alokujesz zasoby, zależy to od Ciebie, aby upewnić się, że są prawidłowo utylizowane. W powyższym kodzie nie masz możliwości śledzenia, które wątki są wykonywane lub z którymi wątkami są powiązane, ManualResetEvent. Jeśli chcesz się upewnić, że MRE jest prawidłowo utylizowany, musisz go śledzić, nie tylko śledzić MRE, ale także, które wątki go używają, które wątki zakończyły swoją pracę i otrzymywać powiadomienia, gdy wszystkie wątki są robione po to, aby można było pozbyć się rzeczy.

W twojej szczególnej sytuacji, jeśli naprawdę musisz użyć MRE w ten sposób, prawdopodobnie utworzyłbym strukturę danych, która zawiera odniesienia do wątków i MRE, i CountdownEvent, którą wątki sygnalizują, gdy skończą. Coś jak:

class WorkUnit 
{ 
    public List<Thread> Threads; 
    public ManualResetEvent MRE; 
    public CountdownEvent CE; 
} 

Teraz, gdy wątek zakończy robi to:

workUnit.CE.Signal(); 

innej części programu (prawdopodobnie główny wątek) sprawdza listę jednostek pracy okresowej. Dla każdej pozycji na liście jest to następujące:

if (workUnit.CE.WaitOne(0)) 
{ 
    foreach (Thread t in workUnit.Threads) 
    { 
     t.Join(); 
    } 
    // dispose the MRE and the CE 
    // and remove the work unit from the list 
} 

Tak, to dużo pracy. Najlepiej, jeśli uda ci się zorganizować swój program, aby nie robić tego w ten sposób.

+0

Dzięki Jim. Jedynym problemem jest to, że nie wiem, ile wątków będzie czekać na MRE, i dlatego nie mogę zainicjować CountDownEvent. Ale masz rację, że powinienem rozważyć projekt, który wie, kiedy MRE nie jest już potrzebny. Obecnie nie ma wątku czekającego na koniec wątków roboczych, ponieważ obliczyć niektóre wartości i wyświetlić wynik w kontrolkach. Po tym zadaniu (oh tak, używam zadań zamiast wątków, ale myślę, że problem jest nadal ten sam, ponieważ zadanie może ustawić CountDownEvent za pomocą ContinueWith) kończy się i nie ma kodu, który czekałby na to jawnie. –

+0

Znalazłem rozwiązanie dla moich spraw. Wątek ustawiający jest tworzony i uruchamiany tylko w jednej metodzie, która zwraca MRE. Osoba wywołująca tę metodę wie o MRE i propaguje ją do wielu wątków, ale wie o odbiornikach. Jestem w stanie opakować MRE w obiekt obsługi, który zarządza odbiornikami MRE i czekać, aż się skończy. Po tym MRE może zostać zwolniony. Dzięki za pomoc. –

Powiązane problemy