2012-05-22 17 views
7

Estoy tratando de configurar múltiples BackgroundWorker s para hacer el trabajo y cuando no esté ocupado empiezo a hacer el siguiente trabajo. Parece que no puedo hacer que funcionen correctamente. Tengo el siguiente código.C# Multiple BackgroundWorkers

Cuando configuro FilesToProcess igual o inferior a funciona perfectamente, aunque si lo hago más alto, la aplicación se congela.

Estoy seguro de que es algo simple, pero no puedo verlo.

Gracias por cualquier ayuda :)

Jay

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows.Forms; 

namespace bgwtest 
{ 
    public partial class Form1 : Form 
    { 
     private const int MaxThreads = 20; 
     private const int FilesToProcess = 21; 
     private BackgroundWorker[] threadArray = new BackgroundWorker[MaxThreads]; 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1Load(object sender, EventArgs e) 
     { 
      InitializeBackgoundWorkers(); 
     } 

     private void InitializeBackgoundWorkers() 
     { 
      for (var f = 0; f < MaxThreads; f++) 
      { 
       threadArray[f] = new BackgroundWorker(); 
       threadArray[f].DoWork += new DoWorkEventHandler(BackgroundWorkerFilesDoWork); 
       threadArray[f].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerFilesRunWorkerCompleted); 
       threadArray[f].WorkerReportsProgress = true; 
       threadArray[f].WorkerSupportsCancellation = true; 
      } 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      for (var f = 0; f < FilesToProcess; f++) 
      { 
       var fileProcessed = false; 
       while (!fileProcessed) 
       { 
        for (var threadNum = 0; threadNum < MaxThreads; threadNum++) 
        { 
         if (!threadArray[threadNum].IsBusy) 
         { 
          Console.WriteLine("Starting Thread: {0}", threadNum); 

          threadArray[threadNum].RunWorkerAsync(f); 
          fileProcessed = true; 
          break; 
         } 
        } 
        if (!fileProcessed) 
        { 
         Thread.Sleep(50); 
        } 
       } 
      } 
     } 

     private void BackgroundWorkerFilesDoWork(object sender, DoWorkEventArgs e) 
     { 
      ProcessFile((int)e.Argument); 

      e.Result = (int)e.Argument; 
     } 

     private static void ProcessFile(int file) 
     { 
      Console.WriteLine("Processing File: {0}", file); 
     } 

     private void BackgroundWorkerFilesRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Error != null) 
      { 
       MessageBox.Show(e.Error.Message); 
      } 

      Console.WriteLine("Processed File: {0}", (int)e.Result); 
     } 
    } 
} 
+1

Sé que estás preguntando por 'BackgroundWorker', pero ¿por qué no utilizar TPL o Rx? Harían esto mucho más simple. – Enigmativity

+3

Está creando un punto muerto al dormir en el subproceso de interfaz de usuario. Evitar que se ejecuten los controladores de eventos RunWorkerCompleted. –

Respuesta

7

El problema parece ser que sus trabajadores están nunca se completan. Por qué esto es, no estoy seguro; tiene algo que ver con el hecho de que el método (y el hilo) del que los está ejecutando no se está completando. Yo era capaz de resolver el problema mediante la creación de otro trabajador para asignar archivos a la matriz trabajador:

private BackgroundWorker assignmentWorker; 

    private void InitializeBackgoundWorkers() { 
     assignmentWorker = new BackgroundWorker(); 
     assignmentWorker.DoWork += AssignmentWorkerOnDoWork; 
     // ... 
    } 

    private void AssignmentWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs) { 
     for(var f = 0; f < FilesToProcess; f++) { 
      var fileProcessed = false; 
      while(!fileProcessed) { 
       for(var threadNum = 0; threadNum < MaxThreads; threadNum++) { 
        if(!threadArray[threadNum].IsBusy) { 
         Console.WriteLine("Starting Thread: {0}", threadNum); 

         threadArray[threadNum].RunWorkerAsync(f); 
         fileProcessed = true; 
         break; 
        } 
       } 
       if(!fileProcessed) { 
        Thread.Sleep(50); 
        break; 
       } 
      } 
     } 
    } 

    private void button1_Click(object sender, EventArgs e) { 
     assignmentWorker.RunWorkerAsync(); 
    } 

No estoy feliz con esta respuesta porque no sé por qué, exactamente, no funcionó como originalmente lo diseñaste. ¿Tal vez alguien más puede responder eso ...? Al menos esto te dará una versión funcional.

EDITAR: La versión original no funcionó porque el BackgroundWorkerFilesRunWorkerCompleted se ejecuta en el mismo subproceso que button1_Click (el subproceso de la interfaz de usuario). Como no está liberando el subproceso de interfaz de usuario, el subproceso nunca se marca como completo.