Как я могу выполнить ThreadPool.Join? - PullRequest
5 голосов
/ 06 августа 2010

Я пишу службу Windows, которая использует ThreadPool.QueueUserWorkItem(). Каждый поток является недолгой задачей.

Когда служба остановлена, мне нужно убедиться, что все потоки, которые в данный момент выполняются, завершены. Есть ли какой-нибудь способ ожидания, пока очередь не очистится?

Ответы [ 2 ]

8 голосов
/ 06 августа 2010

Вы можете создать событие (например, ManualResetEvent) в каждом потоке и сохранить его в синхронизированном списке (используя конструкцию lock). Установите событие или удалите его из списка после завершения задачи.

Если вы хотите присоединиться, вы можете использовать WaitHandle.WaitAll ( документация MSDN ), чтобы дождаться оповещения обо всех событиях.

Это хак, но я не понимаю, как свести это к чему-то более простому!


Редактировать: кроме того, вы можете убедиться, что новые события не публикуются, а затем подождать пару секунд. Если они действительно недолговечны, у вас не будет проблем. Еще проще, но более хакерски.

Наконец, если это всего лишь короткий промежуток времени, служба не завершит работу, пока все потоки не прекратятся (если они не являются фоновыми потоками); так что если это короткий промежуток времени, менеджер службы контроля не будет возражать, или около того - вы можете просто оставить их до истечения срока действия - по моему опыту.

3 голосов
/ 09 августа 2010

Стандартный шаблон для этого - использовать счетчик, который содержит количество ожидающих рабочих элементов, и один ManualResetEvent, который сигнализируется, когда счетчик достигает нуля. Как правило, это лучше, чем использовать WaitHandle для каждого рабочего элемента, поскольку он не очень хорошо масштабируется при большом количестве одновременных рабочих элементов. Кроме того, некоторые из статических методов WaitHandle в любом случае принимают не более 64 экземпляров.

// 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(); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...