一個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中增加了事件的訂閱委托程序

   其他,讀代碼吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM