1. 程式人生 > >一個C# (隊列多任務+多線程處理)對象的winform demo

一個C# (隊列多任務+多線程處理)對象的winform demo

blog exception nerd row 部分 主體 如何 windows prot

閱讀本文前,先閱讀: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