一个C# (队列多任务+多线程处理)对象的winform demo

Posted dmyjcb2019

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个C# (队列多任务+多线程处理)对象的winform demo相关的知识,希望对你有一定的参考价值。

阅读本文前,先阅读:https://www.cnblogs.com/zetee/p/3487084.html 

该文中构建多线程任务的思路,与delphi下构建多任务线程池的方式类似,实现繁多的任务用一定数量的线程进行处理。对并发线程的控制,是善用多线程的技巧之一,线程并不是越多越好。

本文另外的一个目的:让读者在winform下使用该对象。废话不说,上代码。

(1)队列改造

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace MTHdQueue
{

public class DownLoadFile
{
    public string FileName { get; set; }

}


public  class QueueThreadBase
{
    #region 变量&属性

    /// 待处理结果

    private class PendingResult
    {
        /// 待处理值
        public DownLoadFile PendingValue { get; set; }

        /// 是否有值
        public bool IsHad { get; set; }
    }

    /// 线程数
    public int ThreadCount
    {
        get { return this.m_ThreadCount; }
        set { this.m_ThreadCount = value; }
    }
    private int m_ThreadCount = 5;

    /// 取消=True
    public bool Cancel { get; set; }

    /// 线程列表
    List<Thread> m_ThreadList;

    /// 完成队列个数
    private volatile int m_CompletedCount = 0;

    /// 队列总数
    private int m_QueueCount = 0;

    /// 全部完成锁
    private object m_AllCompletedLock = new object();

    /// 完成的线程数

    private int m_CompetedCount = 0;

    /// 队列锁

    private object m_PendingQueueLock = new object();
    private Queue<DownLoadFile> m_InnerQueue; //--内部队列..
    //public DownLoadFile Peek()
    //{
    //    return m_InnerQueue.Dequeue();
    //}
    //public void AddQueue(DownLoadFile ff)
    //{
    //    try
    //    {
    //        m_InnerQueue.Enqueue(ff);
    //        //this.m_QueueCount = m_InnerQueue.Count;
    //    }
    //    catch
    //    {
    //        throw;
    //    }
    //}
    #endregion

    #region 事件相关
    //---开始一个任务的事件...
    public event Action<DownLoadFile> OneJobStart;
    private void OnOneJobStart(DownLoadFile pendingValue)
    {
        if (OneJobStart != null)
        {
            try
            {
                //MessageBox.Show("所有任务完成!");
                OneJobStart(pendingValue);//--一个任务开始了..
            }
            catch { }
        }

    }



    /// 全部完成事件
    public event Action<CompetedEventArgs> AllCompleted;
    /// 单个完成事件
    public event Action<DownLoadFile, CompetedEventArgs> OneCompleted;
    /// 引发全部完成事件
    private void OnAllCompleted(CompetedEventArgs args)
    {
        if(AllCompleted != null)
        {
            try
            {
                //MessageBox.Show("所有任务完成!");
                AllCompleted(args);//全部完成事件
            }
            catch { }
        }
    }

    /// 引发单个完成事件
    private void OnOneCompleted(DownLoadFile pendingValue, CompetedEventArgs args)
    {
        if(OneCompleted != null)
        {
            try
            {
                //MessageBox.Show("单个任务完成!");
                OneCompleted(pendingValue, args);
            }
            catch { }
        }
    }
    #endregion

    #region 构造

    //public QueueThreadBase(IEnumerable<T> collection)
    //{
    //    m_InnerQueue = new Queue<T>(collection);
    //    this.m_QueueCount = m_InnerQueue.Count;
    //}

    public QueueThreadBase(IEnumerable<DownLoadFile> collection)
    {
        m_InnerQueue = new Queue<DownLoadFile>(collection);
        this.m_QueueCount = m_InnerQueue.Count;
    }

    //--- 无参数的构造函数,需要向队列中填充元素...
    public QueueThreadBase()
    {
        m_InnerQueue = new Queue<DownLoadFile>();
        this.m_QueueCount = m_InnerQueue.Count;
    }

    #endregion

    #region 主体

    /// 初始化线程
    private void InitThread()
    {
        m_ThreadList = new List<Thread>();

        for(int i = 0; i < ThreadCount; i++)
        {
            Thread t = new Thread(new ThreadStart(InnerDoWork));
            m_ThreadList.Add(t);
            t.IsBackground = true;
            t.Start();
        }
    }

    /// 开始
    public void Start()
    {
        InitThread();
    }

    /// 线程工作
    private void InnerDoWork()
    {
        try
        {
            Exception doWorkEx = null;
            DoWorkResult doworkResult = DoWorkResult.ContinueThread;
            var t = CurrentPendingQueue;
            OnOneJobStart(t.PendingValue); 

            while(!this.Cancel && t.IsHad)
            {
                try
                {
                    doworkResult = DoWork(t.PendingValue);
                }
                catch(Exception ex)
                {
                    doWorkEx = ex;
                }

                m_CompletedCount++;
                int precent = m_CompletedCount * 100 / m_QueueCount;
                OnOneCompleted(t.PendingValue, new CompetedEventArgs() { CompetedPrecent = precent, InnerException = doWorkEx });

                if(doworkResult == DoWorkResult.AbortAllThread)
                {
                    this.Cancel = true;
                    break;
                }
                else if(doworkResult == DoWorkResult.AbortCurrentThread)
                {
                    break;
                }

                t = CurrentPendingQueue;
            }

            lock(m_AllCompletedLock)
            {
                m_CompetedCount++;

                if(m_CompetedCount == m_ThreadList.Count)
                {
                    OnAllCompleted(new CompetedEventArgs() { CompetedPrecent = 100 });
                }
            }
        }
        catch
        {
            throw;
        }
    }


    protected  DoWorkResult DoWork(DownLoadFile pendingValue)
    {
        try
        {
            string jna = pendingValue.FileName;
            //MessageBox.Show("正在执行任务" + jna);
            //--- 这里如何通知主界面,任务正在执行...
            //for(int i = 0; i < 5; i++)
            //{
            //    Console.WriteLine("任务名:{0} 正在执行第{1}次", jna, i);
            //}
            //..........多线程处理....
            return DoWorkResult.ContinueThread;//没有异常让线程继续跑..
        }
        catch(Exception)
        {
            return DoWorkResult.AbortCurrentThread;//有异常,可以终止当前线程.当然.也可以继续,
            //return  DoWorkResult.AbortAllThread; //特殊情况下 ,有异常终止所有的线程...
        }
    }

    /// 获取当前结果
    private PendingResult CurrentPendingQueue
    {
        get
        {
            lock(m_PendingQueueLock)
            {
                PendingResult t = new PendingResult();

                if(m_InnerQueue.Count != 0)
                {
                    t.PendingValue = m_InnerQueue.Dequeue();
                    t.IsHad = true;
                }
                else
                {
                    t.PendingValue = default(DownLoadFile);
                    t.IsHad = false;
                }

                return t;
            }
        }
    }

    #endregion


}

#region 相关类&枚举

/// dowork结果枚举
public enum DoWorkResult
{
    /// 继续运行,默认
    ContinueThread = 0,
    /// 终止当前线程
    AbortCurrentThread = 1,
    /// 终止全部线程
    AbortAllThread = 2
}

/// 完成事件数据
public class CompetedEventArgs : EventArgs
{
    public CompetedEventArgs()
    {
    }
    /// 完成百分率
    public int CompetedPrecent { get; set; }
    /// 异常信息
    public Exception InnerException { get; set; }
}
#endregion

}

(2)winform 代码

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

namespace MyMTHdQueueWinDemo
{
public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    public delegate void InvokeMsg0(DownLoadFile x);
    public void ShowOneStartMsg(DownLoadFile x)
    {
        if(this.tb5.InvokeRequired)
        {
            InvokeMsg0 msgCallback = new InvokeMsg0(ShowOneStartMsg);
            tb5.Invoke(msgCallback, new object[] { x });
        }
        else
        {
            
            tb5.Text += x.FileName + " begin!" + Environment.NewLine;
        }
    }



    public delegate void InvokeMsg2(CompetedEventArgs args);
    public void ShowAllDoneMsg(CompetedEventArgs args)
    {
        if(this.tb5.InvokeRequired)
        {
            InvokeMsg2 msgCallback = new InvokeMsg2(ShowAllDoneMsg);
            tb5.Invoke(msgCallback, new object[] { args });
        }
        else
        {
            tb5.Text +=  "完成率:" + Convert.ToString(args.CompetedPrecent) + "%  All Job finished!" + Environment.NewLine;
        }
    }



    public delegate void InvokeMsg1(DownLoadFile x, CompetedEventArgs args);
    public void ShowOneDoneMsg(DownLoadFile x, CompetedEventArgs args)
    {
        if(this.tb5.InvokeRequired)
        {
            InvokeMsg1 msgCallback = new InvokeMsg1(ShowOneDoneMsg);
            tb5.Invoke(msgCallback, new object[] { x, args });
        }
        else
        {
            
            tb5.Text += x.FileName + " finished!" + "  完成率:" + Convert.ToString(args.CompetedPrecent) + "%  " + Environment.NewLine;
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        DownLoadFile fd1 = new DownLoadFile();
        fd1.FileName = "myfile.txt";
        DownLoadFile fd2 = new DownLoadFile();
        fd2.FileName = "myfile2.txt";
        DownLoadFile fd3 = new DownLoadFile();
        fd3.FileName = "myfile3.txt";

        DownLoadFile fd4 = new DownLoadFile();
        fd4.FileName = "myfile4.txt";
        DownLoadFile fd5 = new DownLoadFile();
        fd5.FileName = "myfile5.txt";

        
        List<DownLoadFile> Quefd = new List<DownLoadFile>();
        Quefd.Add(fd1);
        Quefd.Add(fd2);
        Quefd.Add(fd3);
        Quefd.Add(fd4);
        Quefd.Add(fd5);
        QueueThreadBase thfd = new QueueThreadBase(Quefd);
        thfd.OneJobStart += ShowOneStartMsg;
        thfd.OneCompleted += ShowOneDoneMsg;
        thfd.AllCompleted += ShowAllDoneMsg;
        thfd.Start();
    }
}
}

(3)演示图片

技术分享图片

(4)重要说明: 

      A)首先将基类改造成了非抽象类,将部分变量类型的定义提出到类的外部

      B)增加了一个表示"任务开始“的事件

      C)在winform中增加了事件的订阅委托程序

   其他,读代码吧

以上是关于一个C# (队列多任务+多线程处理)对象的winform demo的主要内容,如果未能解决你的问题,请参考以下文章

队列与多线程间关系——个人理解

C#多线程处理多个队列数据的方法

C# 多线程同步访问一个文件怎么处理

C#多线程の多个线程处理一个任务,然后执行其余

iOS 开发--多线程

多线程批处理队列