2010-08-06 10 views
5

Piszę usługę Windows, która używa ThreadPool.QueueUserWorkItem(). Każdy wątek jest zadaniem krótkotrwałym.Jak mogę wykonać ThreadPool.Join?

Po zatrzymaniu usługi muszę się upewnić, że wszystkie wątki, które obecnie są wykonywane, są kompletne. Czy jest jakiś sposób czekania, aż kolejka się oczyści?

Odpowiedz

8

może utworzyć zdarzenia (np ManualResetEvent) w każdej z nici, i utrzymywać je w sposób zsynchronizowany listy (stosując lock konstrukcję). Ustaw zdarzenie lub usuń je z listy po zakończeniu zadania.

Jeśli chcesz dołączyć, możesz użyć WaitHandle.WaitAll (MSDN documentation), aby poczekać, aż wszystkie zdarzenia zostaną zasygnalizowane.

To jest hack, ale nie widzę sposobu, aby zmniejszyć go do czegoś prostszego!


Edytuj: dodatkowo możesz upewnić się, że żadne nowe wydarzenia nie zostaną opublikowane, a następnie odczekać kilka sekund. Jeśli rzeczywiście są krótkotrwałe, nie będziesz miał problemu. Jeszcze prostsze, ale bardziej odrażające.

Wreszcie, jeśli jest to tylko krótki okres czasu, usługa nie zakończy pracy, dopóki wszystkie wątki nie zginą (chyba że są wątkami tła); więc jeśli jest to krótki okres czasu, menedżer kontroli serwisowej nie będzie miał nic przeciwko drugiej osobie - możesz po prostu zostawić je na wygaśnięcie - z mojego doświadczenia.

+0

Powinny być krótkotrwałe, ale dla mojego przypadku użycia, potrzebuję więcej pewności niż "powinien działać". Zastanawiam się nad użyciem licznika wątków z blokadą do śledzenia liczby wątków w puli i czekania na to zero. – recursive

+0

Właściwie to lubię twoją pierwszą sugestię lepiej niż licznik. – recursive

3

Standardowy wzór wykonania tej czynności polega na użyciu licznika, który przechowuje liczbę oczekujących pozycji roboczych i jednego ManualResetEvent, który jest sygnalizowany, gdy licznik osiągnie zero. Jest to generalnie lepsze niż użycie WaitHandle dla każdego elementu pracy, ponieważ nie skaluje się bardzo dobrze, gdy istnieje wiele równoczesnych elementów pracy. Ponadto, niektóre statyczne metody WaitHandle akceptują maksymalnie tylko 64 wystąpienia.

// Initialize to 1 because we are going to treat the current thread as 
// a work item as well. This is to avoid a race that could occur when 
// one work item gets queued and completed before the next work item 
// is queued. 
int count = 1; 
var finished = new ManualResetEvent(false); 
try 
{ 
    while (...) 
    { 
    Interlocked.Increment(ref counter); 
    ThreadPool.QueueUserWorkItem( 
     delegate(object state) 
     { 
     try 
     { 
      // Your task goes here. 
     } 
     finally 
     { 
      // Decrement the counter to indicate the work item is done. 
      if (Interlocked.Decrement(ref count) == 0) 
      { 
      finished.Set(); 
      } 
     } 
     }); 
    } 
} 
finally 
{ 
    // Decrement the counter to indicate the queueing thread is done. 
    if (Interlocked.Decrement(ref count) == 0) 
    { 
    finished.Set(); 
    } 
} 
finished.WaitOne(); 
Powiązane problemy