1. 設計線程池遵循的規則
我們應該設計通用的線程池,那麼該怎麼設計呢,其實就是通過回調函數,將線程函數和參數都用void*來表示,這樣用戶可以定義自己的回調函數,而參數的話可以放在結構體裏面,這樣每個客戶都可以使用該線程池來調用自己的函數,並且可以傳遞多個入參。
2. 什麼是線程池
顧名思義,就是多個線程事先已經建立好了,放在一個池子裏,當有需要的時候拿來用,不需要的時候還到池子裏去。
3. 線程池的作用
第一,可以實現代碼的重用,不必每次都去調用線程api來實現;
第二,減少資源的損耗,避免了頻繁的創建和銷燬線程所帶來的資源損耗;
第三,方便管理,我們可以根據機器情況來決定啓多少個線程,並且可以知道哪個線程正在使用,哪個沒有被使用;
4. 線程池的實現
假定一個線程就是一個任務的話,線程池就是多個任務放入一個隊列,需要的時候我們啓動這個任務,不需要的時候,停止這個任務,並且會有一個標誌來表示任務是啓動還是停止狀態。
例如:
空間和線程事先已經初始化好,需要執行任務時,修改執行標誌,傳入函數指針和參數指針,執行,執行完畢後又放入未使用隊列;
在此過程中需用到互斥鎖和條件變量,每個子線程在執行完任務後,會阻塞在條件變量那裏,一旦主線程有任務的話,就通過條件變量通知到子線程,子線程就會重新啓動,開始執行;
一個簡單線程池結構設計如下:
typedef struct ts_queue_item TSQItem;
struct ts_queue_item{
void *data;
struct ts_queue_item *next;
};
typedef struct ts_queue TSQueue;
//一個鏈表隊列,記錄鏈表頭、尾、元素個數以及預先申請的空白鏈表
struct ts_queue{
TSQItem *head;
TSQItem *tail;
pthread_mutex_t lock;
TSQItem *cqi_freelist; //預先申請的空白鏈表
pthread_mutex_t cqi_freelist_lock;
unsigned count;
};
5. 線程池設計步驟
線程池設計:
- 限制最多能起多少個線程
- 初始化起指定數量的線程,讓他們處於等待狀態,當有任務來時將任務傳遞給線程進行處理
- 當啓動線程數量超過最大值時再有任務來要麼拒絕要麼放入隊列等待
- 使用單例模式,一個程序中只會有一個線程池,同時寫一組接口管理線程池實例
- 當有任務時,隊列中空閒線程數量變少
- 當任務完成時,釋放相應的線程