C# 自定義固定數量線程池

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace A9AgentApp.Task
{
    public class CustomThread
    {
        #region Variable
        //一個AutoResetEvent實例
        private AutoResetEvent _locks = new AutoResetEvent(false);

        //一個Thread實例
        private Thread _thread;

        // 綁定回調方法,就是外部實際執行的任務
        public WaitCallback _taskAction;

        //定義一個事件用來綁定工作完成後的操作
        public event Action<CustomThread> WorkCompleted;

        /// <summary>
        ///設置線程擁有的Key
        /// </summary>
        public string Key { get; set; }

        /// <summary>
        /// 當前線程消息輸出Action
        /// </summary>
        public Action<String> MessageWriterAction;
        #endregion

        //線程需要做的工作
        private void Work()
        {
            while (true)
            {
                //判斷信號狀態,如果有set那麼 _locks.WaitOne()後的程序就繼續執行
                _locks.WaitOne();
                // 將當前線程實例傳到Action裏
                _taskAction(this);
                // Console.WriteLine("Thread:" + Thread.CurrentThread.ManagedThreadId + "workComplete");
                //執行完成事件
                WorkCompleted(this);
            }
        }

        #region event
        //構造函數
        public CustomThread()
        {
            // 初始化線程
            _thread = new Thread(Work);
            _thread.IsBackground = true;
            Key = Guid.NewGuid().ToString();
            //線程開始執行
            _thread.Start();
            Console.WriteLine("Thread:" + _thread.ManagedThreadId + " has been created!");
        }

        //Set開起信號
        public void Active()
        {
            _locks.Set();
        }

        #endregion
    }
    public class CustomFixedThreadPool
    {
        #region Variable
        //創建的線程數
        private int TreadCount = 6;
        //空閒線程隊列
        private Queue<CustomThread> _freeThreadQueue;
        //工作線程字典(爲什麼?)
        private Dictionary<string, CustomThread> _workingDictionary;
        //空閒隊列,存放需要被執行的外部函數
        private Queue<WaitCallback> _waitTaskQueue;

        #endregion

        #region Event
        /// <summary>
        /// 自定義線程池的構造函數
        /// </summary>
        /// <param name="MessageWriteActions">線程輸出消息方法列表</param>
        public CustomFixedThreadPool(List<Action<String>> MessageWriteActions)
        {
            _workingDictionary = new Dictionary<string, CustomThread>();
            _freeThreadQueue = new Queue<CustomThread>();
            _waitTaskQueue = new Queue<WaitCallback>();

            CustomThread task = null;
            //產生固定數目的線程
            for (int i = 0; i < TreadCount; i++)
            {
                task = new CustomThread();
                //給每一個任務綁定事件
                if (MessageWriteActions.Any())
                {
                    task.MessageWriterAction = MessageWriteActions[i % MessageWriteActions.Count];
                }
                else
                {
                    task.MessageWriterAction = (msg) => { };
                }
                task.WorkCompleted += new Action<CustomThread>(WorkComplete);
                //將每一個新創建的線程放入空閒隊列中
                _freeThreadQueue.Enqueue(task);
            }
        }

        //線程任務完成之後的工作
        void WorkComplete(CustomThread obj)
        {
            lock (this)
            {
                //將線程從字典中排除
                _workingDictionary.Remove(obj.Key);
                //將該線程放入空閒隊列
                _freeThreadQueue.Enqueue(obj);

                //判斷是否等待隊列中有任務未完成
                if (_waitTaskQueue.Count > 0)
                {
                    //取出一個任務
                    WaitCallback item = _waitTaskQueue.Dequeue();
                    CustomThread newTask = null;
                    //空閒隊列中取出一個線程
                    newTask = _freeThreadQueue.Dequeue();
                    // 線程執行任務
                    newTask._taskAction = item;
                    //把線程放入到工作隊列當中
                    _workingDictionary.Add(newTask.Key, newTask);
                    //設置信號量
                    newTask.Active();
                    return;
                }
                else
                {
                    return;
                }
            }
        }

        //添加任務到線程池
        public void AddTaskItem(WaitCallback taskItem)
        {
            lock (this)
            {
                CustomThread task = null;
                //判斷空閒隊列是否存在線程
                if (_freeThreadQueue.Count > 0)
                {
                    //存在線程,取出一個線程
                    task = _freeThreadQueue.Dequeue();
                    //將該線程放入工作隊列
                    _workingDictionary.Add(task.Key, task);
                    //執行傳入的任務
                    task._taskAction = taskItem;
                    //設置信號量
                    task.Active();
                    return;
                }
                else
                {
                    //空閒隊列中沒有空閒線程,就把任務放到等待隊列中
                    _waitTaskQueue.Enqueue(taskItem);
                    return;
                }
            }
        }
        #endregion
    }
   
}

  

2.使用方法 (初始化線程池)

 infoLabels = new List<Label>() { this.lbl_info1, this.lbl_info2, this.lbl_info3, this.lbl_info4, this.lbl_info5, this.lbl_info6 };
            List<Action<String>> infoLabelWriters = new List<Action<string>>();
            foreach(Label label in infoLabels)
            {
                infoLabelWriters.Add((msg) => label.CrossThreadRun(()=>label.Text = msg));
            }

            customThreadPool = new CustomFixedThreadPool(infoLabelWriters);

3. 使用方法(完成任務)

for(int i = 0; i < 10; i++)
            {
                customThreadPool.AddTaskItem((t) =>
                {
                    var msgWriter = ((CustomThread)t).MessageWriterAction;
                    for(int j = 0; j < 1000; j++)
                    {
                        msgWriter("正在執行第"+(1+j).ToString()+"/1000 條");
                        Thread.Sleep(10);
                    }
                    msgWriter("執行完成!");
                });
            }

 或 (增加任務完成標識)

            ((Button)sender).Enabled = false;
            int flag = 0;
            for (int i = 0; i < 10; i++)
            {
                customThreadPool.AddTaskItem((t) =>
                {
                    Interlocked.Increment(ref flag);
                    var msgWriter = ((CustomThread)t).MessageWriterAction;
                    for(int j = 0; j < 1000; j++)
                    {
                        msgWriter("正在執行第"+(1+j).ToString()+"/1000 條");
                        Thread.Sleep(10);
                    }
                    msgWriter("執行完成!");
                    Interlocked.Decrement(ref flag);

                    if (flag == 0)
                    {
                        ControlUtil.CrossThreadRun((Button)sender, () => ((Button)sender).Enabled = true);
                    }
                });
            }

 

4. 輔助類

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

namespace A9AgentApp.utils
{
   public static class ControlUtil
    {
        /// <summary>
     /// 跨線程訪問控件 在控件上執行委託
     /// </summary>
     /// <param name="ctl">控件</param>
     /// <param name="del">執行的委託</param>
        public static void CrossThreadRun(this Control ctl, ThreadStart process)
        {
            if (process == null) return;
            if (ctl.InvokeRequired) { ctl.Invoke(process, null); }
            else
            {
                process();
            }
        }

        /// <summary>
        /// 跨線程訪問控件 在控件上執行委託
        /// </summary>
        /// <param name="ctl">控件</param>
        /// <param name="del">執行的委託</param>
        public static Object CrossThreadCall (this Control ctl, Func<Object> func)
        {
            if (ctl.InvokeRequired) {return  ctl.Invoke(func, null); }
            else
            {
               return func();
            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章