中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#如何實現自定義線程池

發布時間:2022-07-19 09:21:21 來源:億速云 閱讀:309 作者:iii 欄目:開發技術

這篇文章主要介紹了C#如何實現自定義線程池的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C#如何實現自定義線程池文章都會有所收獲,下面我們一起來看看吧。

在項目中如果是web請求時候,IIS會自動分配一個線程來進行處理,如果很多個應用程序共享公用一個IIS的時候,線程分配可能會出現一個問題(當然也是我的需求造成的)

之前在做項目的時候,有一個需求,就是當程序啟動的時候,希望能夠啟動一定數目的線程,然后每一個線程始終都是在運行的狀態,不進行釋放,然后循環去做一些事情。那么IIS的線程管理可能就不是我想要的,因為我想我的一些程序,只用我開啟的線程來做工作。也就是說我想模擬一個線程池,每次有一個調用的時候從自定義線程池中取出一個,用完再放回去。

談談我的思路:

1.程序一啟動就通過for循環來創建,一定數目的線程(這個數目是可以配置的)

2.至少要有三個容器來存儲線程,分別是工作線程隊列和空閑線程隊列以及等待隊列

3.使用線程中的AutoResetEvent類,初始每一個線程都是unsignaled狀態,線程一啟動就一直在循環調用WaitOne()方法,那么每次外部調用的時候,都調用一次這個類實例對象的set,線程然后就可以繼續做下面的工作了。

4.至少兩個方法:

第一個開放給外部,讓外部的方法能夠被傳入執行,然后這個方法能夠判斷空閑隊列,等待隊列,以及工作隊列的狀態,如果傳入的時候發現,空閑隊列有空閑的線程就直接,將任務委托給空閑隊列的一個線程執行,否則把它放到等待隊列。

第二個方法,需要能夠將工作完成的線程從工作隊列移動到空閑隊列,然后判斷一下等待隊列是不是有任務,有的話就交給空閑隊列里面的線程來執行。

體思路如上,可以試試先寫一下。

1.因為每個線程都有一個AutoResetEvent的實例,所以最好把Thread進行封裝,變成我們自己的Thread。

    public class Task
    {
        #region Variable
        //一個AutoResetEvent實例
        private AutoResetEvent _locks = new AutoResetEvent(false);
        //一個Thread實例
        private Thread _thread;
        // 綁定回調方法,就是外部實際執行的任務
        public Action _taskAction;

        //定義一個事件用來綁定工作完成后的操作,也就是4中所說的工作隊列向空閑隊列移動
        public event Action<Task> WorkComplete;

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

        #endregion

        //線程需要做的工作
        private void Work()
        {
            while (true)
            {
                //判斷信號狀態,如果有set那么 _locks.WaitOne()后的程序就繼續執行
                _locks.WaitOne();
                _taskAction();
                //執行事件
                WorkComplete(this);
            }
        }

        #region event
        //構造函數
        public Task()
        {
            //スレッドオブジェクトを初期化する
            _thread = new Thread(Work);
            _thread.IsBackground = true;
            Key = Guid.NewGuid().ToString();
            //線程開始執行
            _thread.Start();
        }

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

        #endregion
    }

解釋:上面那個Key的作用,因為多個線程同時進行的時候,我們并不知道哪一個線程的工作先執行完,所以說上面的工作隊列,實際上應該用一個字典來保存,這樣我們就能在一個線程結束工作之后,通過這 里的KEY(每個線程不一樣),來進行定位了。

2.線程封裝好了,然后就可以實現線程池了

    public class TaskPool
    {
        #region Variable
        //創建的線程數
        private int _threadCount;
        //空閑線程隊列
        private Queue<Task> _freeQueue;
        //工作線程字典(為什么?)
        private Dictionary<string, Task> _workingDictionary;
        //空閑隊列,存放需要被執行的外部函數
        private Queue<Action> _waitQueue;
        #endregion

        #region Event
        //自定義線程池的構造函數
        public TaskPool()
        {
            _workingDictionary = new Dictionary<string, Task>();
            _freeQueue = new Queue<Task>();
            _waitQueue = new Queue<Action>();
            _threadCount = 10;

            Task task = null;
            //產生固定數目的線程
            for (int i = 0; i < _threadCount; i++)
            {
                task = new Task();
                //給每一個任務綁定事件
                task.WorkComplete += new Action<Task>(WorkComplete);
                //將每一個新創建的線程放入空閑隊列中
                _freeQueue.Enqueue(task);
            }
        }

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

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

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

解釋:這里的兩個方法,基本符合我的設想,注意每一個方法里面都有lock操作,這就保證了,多個線程進行操作相同的隊列對象的時候,能夠進行互斥。保證一個時間只有一個線程在操作。

測試代碼:

    class Program
    {
        static void Main(string[] args)
        {
            TaskPool _taskPool = new TaskPool();

            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            for (var i = 0; i < 20; i++)
            {
                _taskPool.AddTaskItem(Print);
            }
            Console.Read();
        }

        public static void Print()
        {
            Console.WriteLine("Do Something!");
        }
    }

這里我執行了20次print操作,看看結果是啥:

C#如何實現自定義線程池

從圖中看到20次確實執行了,但是看不到線程是哪些,稍微修改一下自定義的線程池。

1.在自定義線程的構造函數中添加:如下代碼,查看哪些線程被創建了

        public Task()
        {
            _thread = new Thread(Work);
            _thread.IsBackground = true;
            Key = Guid.NewGuid().ToString();
            //線程開始執行
            _thread.Start();
            Console.WriteLine("Thread:"+_thread.ManagedThreadId+" has been created!");
        }

2.在線程完成工作方法之后添加如下代碼,查看哪些線程參與執行任務

        private void Work()
        {
            while (true)
            {
                //判斷信號狀態,如果有set那么 _locks.WaitOne()后的程序就繼續執行
                _locks.WaitOne();
                _taskAction();
                Console.WriteLine("Thread:" + Thread.CurrentThread.ManagedThreadId+"workComplete");
                //執行事件
                WorkComplete(this);
            }
        }

3.修改客戶端程序

    class Program
    {
        static void Main(string[] args)
        {
            TaskPool _taskPool = new TaskPool();

            for (var i = 0; i < 20; i++)
            {
                _taskPool.AddTaskItem(Print);
            }
            Console.Read();
        }

        public static void Print()
        {
            Thread.Sleep(10000);
        }
    }

測試結果:

C#如何實現自定義線程池

關于“C#如何實現自定義線程池”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“C#如何實現自定義線程池”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

禄劝| 西乌珠穆沁旗| 石景山区| 独山县| 肃宁县| 东平县| 华阴市| 玛多县| 桦甸市| 莆田市| 盘山县| 富川| 正安县| 盱眙县| 乌苏市| 旬邑县| 临清市| 无极县| 高要市| 沈阳市| 鄂托克旗| 三穗县| 乌鲁木齐县| 长顺县| 富平县| 曲靖市| 焉耆| 尚志市| 灌云县| 正阳县| 揭西县| 竹北市| 双柏县| 黎平县| 革吉县| 嘉黎县| 东源县| 东阳市| 大名县| 涟源市| 望都县|