2012-09-26 3 views
0

Как узнать, когда все рабочие из цикла закончены? И как «выполнить» bw_RunWorkerCompleted после всех этих работников. Я пробовал несколько способов, но я не смог. Главный рабочий всегда заканчивается первым.Multi-BackgroundWorker

.Net 3,5

http://pastebin.com/kMmajq6f

using System; 
using System.ComponentModel; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

      BackgroundWorker bw = new BackgroundWorker(); 
      bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
      bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
      bw.WorkerSupportsCancellation = true; 
      bw.WorkerReportsProgress = true; 

      bw.RunWorkerAsync(); 

      Console.ReadLine(); 

     } 

     static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      Console.WriteLine("All"); 
     } 

     static void bw_DoWork(object sender, DoWorkEventArgs e) 
     { 
      for (int i = 0; i < 10; i++) 
      { 
       BackgroundWorker inBW = new BackgroundWorker(); 
       inBW.DoWork += new DoWorkEventHandler(inBW_DoWork); 
       inBW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(inBW_RunWorkerCompleted); 

       inBW.RunWorkerAsync(i.ToString()); 
      } 
     } 

     static void inBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      Console.WriteLine(e.Result as String); 
     } 

     static void inBW_DoWork(object sender, DoWorkEventArgs e) 
     { 
      Thread.Sleep(new Random().Next(1000, 5000)); 

      e.Result = e.Argument as string; 
     } 
    } 
} 
+1

Запуск асинхронной операции из асинхронной операции кажется мне бессмысленным. В конце концов, для меня единственной/основной причиной для асинхронных операций является поддержание пользовательского интерфейса. –

+0

В этом случае .Net Framework V4 может помочь с помощью класса Task. Можете ли вы перейти к этой версии или позже? –

+0

Да, это из-за UI –

ответ

2

RunWorkerCompleted обработчик события вызывается как только DoWork возвращает обработчиков событий. В этом случае метод bw_DoWork возвращается, если он откручивает 10 дополнительных BackgroundWorkers.

Я собирался предложить вам использовать CountdownEvent для вашего случая, но понял, что вы на .Net 3.5. В этом случае вы можете создать нечто подобное, используя Pulse and Wait.

+0

Работает с CountdownEvent. Но это хорошее решение? (потому что вы удаляете свой комментарий). –

+0

Я отредактировал мой ответ, чтобы иметь решение для .net 3.5. Я думаю, что с одним сигнальным объектом легче управлять, чем со списком событий сброса вручную, как это было предложено @Makubex. –

3
static int workerCount = 11; // one more for the main BW 
static int completedWorkerCount = 0; 

static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    Console.WriteLine("All"); 
    updateAllWorkersProgress() 
} 

static void inBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    Console.WriteLine(e.Result as String); 
    updateAllWorkersProgress(); 
} 

static void updateAllWorkersProgress() 
{ 
    if (++completedWorkerCount == workerCount) 
    { 
      Console.WriteLine("Everything completed"); 
    } 
} 
+0

Спасибо, это тоже была моя идея, но мне нужно запустить код из bw_RunWorkerCompleted, когда все рабочие закончены. Этот код является всего лишь примером, в реальности у меня гораздо больше кода :) –

+0

В основном мне нужно, чтобы главный рабочий был жив –

+0

Я обновил, чтобы включить всех работников. Есть ли определенный порядок, который вы пытаетесь достичь? – Joe

2

Как Стив предложил использовать Task. Но если вы не на свободе, то создайте дескриптор ожидания для каждого суб-работника и дождитесь их всех в главном рабочем столе bg.

В качестве переменной-члена вы должны иметь список/массив ManualResetEvents и передавать один для каждого суб-работника. Каждый суб-сотрудник будет сигнализировать о событии после его завершения. Главный BG-работник завершат только после того, как все сигналы были получили (использование WaitAll)

Приведи это - Manual Reset Events and WaitAll on MSDN

+0

Обратите внимание, что фоновые рабочие маршалируют поток пользовательского интерфейса в завершенном событии и синхронизируют выполнение всех этих обработчиков. Поскольку они уже синхронизированы, вы можете просто использовать простой счетчик, не беспокоясь о состоянии гонки. – Servy

+0

В этом случае вам нужно будет проверить, достиг ли счетчик указанного счета, чтобы закрыть основного работника. IMO, потраченные впустую циклы CPU. – Makubex