Многопоточная очередь в C # - PullRequest
3 голосов
/ 25 августа 2009

Мне было поручено работать с системой очередей загрузки, но я немного запутался, с чего начать.

По сути, нам нужно иметь что-то вроде менеджера закачек (но не полностью). У нас есть около 20-100 файлов для загрузки, мы даем пользователю пользовательский интерфейс (со списком), чтобы он мог приостанавливать, останавливать или перемещать приоритетные задания.

Что меня смущает, так это структура данных, которую нужно использовать. Приоритетная очередь кажется мне подходящим вариантом моего исследования, но я не совсем понимаю, как заставить его работать. Есть ли у меня фоновый поток, который заглядывает в очередь, выбирает следующую задачу и переносит ее вперед? Мне также нужно обеспечить прогресс при загрузке файлов - они довольно большие, иногда 120 МБ (но локально, поэтому не более 10 минут).

Иногда им нужно приостановить работу и поставить работу выше в очереди, поскольку это считается срочным.

Это не менеджер загрузок, так что никаких проблем с регулированием и т.д. Как люди пишут такие вещи?

Я думал о том, чтобы иметь интерфейс, такой как IDownloadTask, который описывает задачу, которую нужно выполнить, иметь несколько свойств и событие, чтобы показать ее прогресс (который связывается при выполнении задач).

Затем поместите этот IDownloadTask в очередь с приоритетом. Фоновый рабочий забирает его (я думаю, нужно будет синхронизировать PriorityQUeue), а затем выполняет метод .Execute () в реализации интерфейса в отдельном потоке.

Это звучит разумно? Есть ли конкретные примеры, которые кто-нибудь может мне показать где-нибудь?

EDIT

Ух, спасибо за ответ и за доверие, должен отметить, что я использую .NET 2.0 (мы не можем двигаться дальше из-за требований совместимости Windows для Windows 9x).

Ответы [ 3 ]

2 голосов
/ 25 августа 2009

Что касается отслеживания прогресса, ваш поток может сообщать о прогрессе, используя события, а также завершение. Вот пример с событием завершения, но та же концепция будет работать для события обновления состояния. Вы просто изменили бы класс, содержащий данные, чтобы он мог передавать информацию о прогрессе.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ThreadWithDataReturnExample
{
    public partial class Form1 : Form
    {
        private Thread thread1 = null;

        public Form1()
        {
            InitializeComponent();

            thread1 = new Thread(new ThreadStart(this.threadEntryPoint));
            Thread1Completed += new AsyncCompletedEventHandler(thread1_Thread1Completed);
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            thread1.Start();
            //Alternatively, you could pass some object
            //in such as Start(someObject);
            //With apprioriate locking, or protocol where
            //no other threads access the object until
            //an event signals when the thread is complete,
            //any other class with a reference to the object 
            //would be able to access that data.
            //But instead, I'm going to use AsyncCompletedEventArgs 
            //in an event that signals completion
        }

        void thread1_Thread1Completed(object sender, AsyncCompletedEventArgs e)
        {
            if (this.InvokeRequired)
            {//marshal the call if we are not on the GUI thread                
                BeginInvoke(new AsyncCompletedEventHandler(thread1_Thread1Completed),
                  new object[] { sender, e });
            }
            else
            {
                //display error if error occurred
                //if no error occurred, process data
                if (e.Error == null)
                {//then success

                    MessageBox.Show("Worker thread completed successfully");
                    DataYouWantToReturn someData = e.UserState as DataYouWantToReturn;
                    MessageBox.Show("Your data my lord: " + someData.someProperty);

                }
                else//error
                {
                    MessageBox.Show("The following error occurred:" + Environment.NewLine + e.Error.ToString());
                }
            }
        }

        #region I would actually move all of this into it's own class
            private void threadEntryPoint()
            {
                //do a bunch of stuff

                //when you are done:
                //initialize object with data that you want to return
                DataYouWantToReturn dataYouWantToReturn = new DataYouWantToReturn();
                dataYouWantToReturn.someProperty = "more data";

                //signal completion by firing an event
                OnThread1Completed(new AsyncCompletedEventArgs(null, false, dataYouWantToReturn));
            }

            /// <summary>
            /// Occurs when processing has finished or an error occurred.
            /// </summary>
            public event AsyncCompletedEventHandler Thread1Completed;
            protected virtual void OnThread1Completed(AsyncCompletedEventArgs e)
            {
                //copy locally
                AsyncCompletedEventHandler handler = Thread1Completed;
                if (handler != null)
                {
                    handler(this, e);
                }
            }
        #endregion

    }
}
1 голос
/ 25 августа 2009

Вот два проекта C #, которые вы, вероятно, можете использовать, чтобы начать работу.

0 голосов
/ 25 августа 2009

Вот мини-реализация, с которой вы можете начать:

C # Потоковая проблема с AutoResetEvent

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

...