【问题标题】:Multi-threaded Queue in C#C#中的多线程队列
【发布时间】:2009-08-25 01:44:37
【问题描述】:

我的任务是开发一个下载排队系统,但我有点不知道从哪里开始。

本质上,我们需要做的是拥有一个下载管理器之类的东西(但不是那么完善)。我们有大约 20-100 个文件要下载,我们为用户提供了一个 UI(带有列表视图)以允许他们暂停、停止或移动优先级的作业。

我对要使用的数据结构感到困惑,优先队列似乎是我研究的一种方式,但我对如何使其发挥作用感到困惑。我是否有一个后台线程可以窥视队列并选择下一个任务并继续执行?在下载文件时,我也需要提供进度 - 它们非常大,有时 120Mb(但它是本地的,所以不超过 10 分钟)。

有时他们需要暂停一项工作,并将一项工作推到队列中更高的位置,因为它被认为是紧急的。

它不是下载管理器,所以没有限制等问题。人们怎么写这样的东西?

我正在考虑有一个像 IDownloadTask 这样的接口,它描述要执行的任务,有一些属性和一个事件来公开它的进度(当任务运行时会连接起来)。

然后将该IDownloadTask 放入优先级队列中。后台工作人员将其拾取(我猜 PriorityQUeue 需要同步),然后在单独的线程上执行接口实现中的 .Execute() 方法。

这听起来合理吗?有没有人可以在某处向我展示的具体示例?

编辑

哇,感谢您的回复和信任投票,我应该提一下我正在使用 .NET 2.0(由于 Windows 9x 的 Windows 兼容性要求,我们不能再提高了)。

【问题讨论】:

  • 你的思路是正确的。
  • 我认为将这个问题分解成更容易回答的较小部分(和单独的问题)可能是个好主意。这种系统的设计是一个多页文档。

标签: c# data-structures multithreading queue cpu


【解决方案1】:

至于跟踪进度,您的线程可以使用事件以及完成来报告进度。这是一个完成事件的示例,但同样的概念也适用于状态更新事件。您只需更改保存数据的类,以便它可以传递有关进度的信息。

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

    }
}

【讨论】:

    【解决方案2】:

    这里有两个 C# 项目,您可以使用它们来帮助您入门。

    【讨论】:

      【解决方案3】:

      这是一个你可以开始的迷你实现:

      C# Threading issue with AutoResetEvent

      您可能希望拥有 1 个以上的处理线程,并且您可能需要将一些通信添加回正在处理的数据,以便您可以暂停等...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-13
        • 2010-10-28
        • 2010-11-15
        • 1970-01-01
        • 1970-01-01
        • 2018-03-09
        • 2013-07-20
        相关资源
        最近更新 更多