2010-08-06 32 views
5

ThreadPool.QueueUserWorkItem() kullanıyor bir windows hizmeti yazıyorum. Her iş parçacığı kısa ömürlü bir görevdir.ThreadPool.Join'i nasıl yapabilirim?

Hizmet durdurulduğunda, şu anda yürütülmekte olan tüm iş parçacıklarının eksiksiz olduğundan emin olmamız gerekir. Kuyruk kendini temizleyene kadar beklemenin bir yolu var mı?

cevap

8

Her iş parçacığında bir olay (ör. ManualResetEvent) oluşturabilir ve senkronize bir listede saklayabilirsiniz (lock yapısını kullanarak). Etkinliği ayarlayın veya görev bittiğinde listeden kaldırın.

Katılmak istediğinizde, tüm olayların bildirilmesini beklemek için WaitHandle.WaitAll (MSDN documentation) kullanabilirsiniz.

Bu bir kesmek ama daha basit bir şeye nasıl indirgemiyorum!


Düzenleme: Ayrıca, yeni olayların gönderilmemesini sağlayabilir, ardından birkaç saniye bekleyebilirsiniz. Eğer gerçekten kısa ömürlülerse, sorun olmaz. Daha basit, ama daha hacky.

Son olarak, eğer çok kısa bir süre varsa, tüm iş parçacıkları ölünceye kadar hizmetten çıkmaz (arka plan iş parçacıkları olmadıkça); Bu yüzden eğer kısa bir süre varsa, servis kontrol müdürü bir ya da daha fazla aklına takılmayacaktır - deneyimlerime göre onları sona erdirebilirsiniz.

+0

Kısa ömürlü olmalılar, fakat kullanım durumum için "çalışmalı" dan daha fazla güvenceye ihtiyacım var. Havuzdaki iş parçacığı sayısını izlemek ve bu sıfıra eşit olarak beklemek için kilitli bir iş parçacığı sayacı kullanmayı düşünüyorum. – recursive

+0

Aslında, ilk önerinizi tezgahtan daha iyi seviyorum. – recursive

3

Bunu yapmak için kullanılan standart desen, sayacın sıfıra ulaşması durumunda işaret edilen bekleyen iş öğelerini ve bir adet ManualResetEvent sayısını içeren bir sayaç kullanmaktır. Bu, her bir iş öğesi için bir çok eş zamanlı iş öğesi olduğunda çok iyi ölçeklenmediğinden genellikle bir WaitHandle kullanmaktan daha iyidir. Ayrıca, bazı statik WaitHandle yönteminin yalnızca en fazla 64 örneğini kabul etmesi gerekir.

// 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();