简体   繁体   English

C#中的多线程队列

[英]Multi-threaded Queue in C#

I've been tasked with working on a download queuing system but I'm a bit confused about where to start. 我的任务是处理下载排队系统,但我对从哪里开始感到困惑。

Essentially what we need to do is to have something like a download manager (but not as fully blown). 基本上我们需要做的就是拥有类似下载管理器的东西(但不是完全成熟)。 We have about 20-100 files to download, we give the user a UI (with a listview) to allow them to pause, stop, or move the priorty of jobs around. 我们有大约20-100个文件要下载,我们为用户提供一个UI(带有列表视图),以允许他们暂停,停止或移动一系列的工作。

What I'm confused about is the data-structure to use, a Priority Queue seems like the way to go from my research, but I'm confused about how to make it work. 令我困惑的是要使用的数据结构,优先级队列似乎是从我的研究中得出的方式,但我对如何使其工作感到困惑。 Do I have a background thread that peeks into the Queue and picks up the next task and carries it forward? 我是否有一个后台线程可以查看队列并获取下一个任务并继续前进? I need to provide progress too as the files are being downloaded - they are quite large, sometimes 120Mb (but its local, so no more than 10mins). 我需要在下载文件时提供进度 - 它们非常大,有时是120Mb(但是它本地,所以不超过10分钟)。

Sometimes they need to pause a job and shove a job higher up in the queue as its deemed urgent. 有时他们需要暂停工作,并将工作推到队列中,因为它被认为是紧急的。

Its not a download manager, so no throttling etc issues. 它不是一个下载管理器,所以没有限制等问题。 How do people write things like this? 人们怎么写这样的东西?

I was thinking of having an interface like IDownloadTask which describes the task to carry out, have a few properties and an event to expose its Progress (which gets wired up when the tasks runs). 我想有一个像IDownloadTask这样的界面来描述要执行的任务,有一些属性和一个事件来公开它的进度(当任务运行时它会被连接起来)。

Then put that IDownloadTask into the queue with a priority. 然后将该IDownloadTask放入具有优先级的队列中。 A background worker picks it up (the PriorityQUeue will need to be synchronised I guess) and then executes the .Execute() method in the interface implementation on a seperate thread. 后台工作程序选择它(我猜想PriorityQeue需要同步)然后在单独的线程上的接口实现中执行.Execute()方法。

Does this sound reasonable? 这听起来合理吗? Are there any concrete examples anyone can show me somewhere? 有什么具体的例子,任何人都可以告诉我某个地方吗?

EDIT 编辑

Wow thanks for the reply and the vote of confidence, I should mention that I'm using .NET 2.0 (we can't move higher because of Windows compatibility requirements for Windows 9x). 哇谢谢你的回复和信任投票,我应该提到我使用的是.NET 2.0(由于Windows 9x的Windows兼容性要求,我们无法提升。)

As for tracking progress, your thread can report progress using events, as well as completion. 至于跟踪进度,您的线程可以使用事件报告进度以及完成。 Here is an example with a completion event, but the same concept would work for a Status update event. 以下是完成事件的示例,但相同的概念适用于状态更新事件。 You'd just change the class that holds the data so that it can pass info about progress. 您只需更改保存数据的类,以便它可以传递有关进度的信息。

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

    }
}

Here are two C# projects that you can probably use to get you started. 这里有两个C#项目,您可以使用这些项目来帮助您入门。

Here are is a mini implementation you can start out with: 这是一个迷你实现,您可以从以下开始:

C# Threading issue with AutoResetEvent C#与AutoResetEvent的线程问题

You will probably want to have more that 1 processing thread, and you will probably need to add some comms back to the piece of data being processed so you can pause etc ... 您可能希望拥有更多的1个处理线程,并且您可能需要将一些通信添加回正在处理的数据中,以便您可以暂停等...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM