閱讀本文前,先閱讀: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中增加了事件的訂閱委托程序
其他,讀代碼吧