C# Несколько BackgroundWorkers

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

когда я поставил FilesToProcess равно или меньше MaxThreads он отлично работает, хотя, если я сделаю его выше, приложение замерзнет.

Я уверен, что это что-то простое, но я просто не могу видеть это.

Спасибо за любую помощь :)

Джей

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 ответов


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

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

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

EDIT: ваша оригинальная версия не работала, потому что BackgroundWorkerFilesRunWorkerCompleted выполняется в том же потоке, как button1_Click (поток пользовательского интерфейса). Поскольку вы не освобождаете поток пользовательского интерфейса, поток никогда не помечается как полный.