1. 程式人生 > >執行緒池 (4)---構造,析構和宣告 (附帶一個測試main)

執行緒池 (4)---構造,析構和宣告 (附帶一個測試main)

先上程式碼,宣告部分

  1 #ifndef _THREAD_POOL_
  2 #define _THREAD_POOL_
  3 
  4 #pragma once
  5 
  6 #include<thread>
  7 #include<condition_variable>
  8 #include<mutex>
  9 #include<shared_mutex>
 10 #include"Loop_Queue.h"
 11 #include<map>
 12 #include<vector>
 13 #include<exception>
 14
15 #ifdef _WIN32 //sleep函式 16 #include<Windows.h> 17 #else 18 #include<unistd.h> 19 #endif // WIN32 20 21 22 #define EACH_MODIFCATION 2 //每次調整的執行緒數 23 24 25 26 27 28 enum RetStatus { // 執行狀態的列舉 29 OK = 0, TODO,NOSUCHWORK, RUNNING, ERR 30 }; 31 32
33 typedef struct { //返回結構體,返回值和執行結果 34 RetStatus flag; 35 void *val; 36 }Ret_t; 37 38 typedef struct Task_t{ 39 int key; 40 void* (*work)(void*); 41 void* arg; 42 43 inline explicit Task_t(const int a=0) { //轉換建構函式,使得可以(T)5 這樣使用 44 key = a;
45 work = NULL; 46 arg = NULL; 47 } 48 }Task_t; 49 50 51 void fun() { 52 Task_t t(5); 53 Task_t a = (Task_t)5; 54 } 55 56 57 58 class ThreadPool 59 { 60 friend void ThreadTask(ThreadPool *pthis); 61 friend void Control(ThreadPool *p); 62 63 64 std::condition_variable TaskCondVar; 65 std::mutex mutexCond; 66 std::mutex TaskQLock; 67 Loop_Queue<Task_t> *TaskQ = NULL; 68 69 70 std::shared_timed_mutex RetTreeLock; 71 std::map<int, Ret_t> RetTree; //結果樹 72 73 std::mutex keyidLock; 74 unsigned int keyid=1; 75 76 std::mutex KillLock; 77 unsigned Kill = 0; //要銷燬的執行緒數 78 79 std::mutex SleepLock; 80 unsigned Sleep = 0; //阻塞執行緒數 81 82 unsigned sumThreads; //匯流排程數 僅由管理者修改 83 unsigned minThreads; //最小執行緒數 初始化後不修改 84 unsigned maxThreads; //最大執行緒數 初始化後不修改 85 bool PoolAlive = true; //執行緒池是否要回收(存活) 86 87 88 89 std::thread *Controller=NULL; 90 91 92 public: 93 94 Ret_t GetResult(int key); //根據key返回任務執行狀態 95 96 int PushTask(void*(*task)(void*),void*argc=NULL,bool ifneedRet=false); //類外呼叫,提交任務,是否需要返回值 97 98 99 100 public: 101 ThreadPool(int minThreads=4,int maxThreads=32,int maxTaskQue=1000); 102 ~ThreadPool(); 103 }; 104 105 106 107 108 #endif // !_THREAD_POOL_

 

windows的sleep和Linux的sleep不一樣,所以只好#ifdef  ,大概是Linux: usleep(微妙) sleep(秒) windows:Sleep(毫秒),只有這部分必須要涉及平臺特性

構造和析構:

 

 1 ThreadPool::ThreadPool(int minThreads,int maxThreads,int maxTaskQueue)    //棧區列表初始化(本來有要初始化的,現在沒了)
 2 {
 3     //不得不說,用c++特性的鎖還能簡化mutex的初始化銷燬等等操作
 4     this->maxThreads = maxThreads;
 5     this->minThreads = minThreads;
 6     sumThreads = minThreads;
 7     TaskQ = new Loop_Queue<Task_t>(maxTaskQueue);    //構造佇列
 8 
 9 
10 
11     //執行緒要最後建立以免上面的物件還沒構造完成就被訪問,
12     Controller = new std::thread(Control, this);            //執行緒池管理者
13     
14     for (int i = 0; i < minThreads; ++i) {
15         std::thread* aThread = new std::thread(ThreadTask, this);
16         aThread->detach();            //暫時就讓子執行緒自生自滅...
17         
18         
19         delete aThread;
20         //new的空間還是要釋放,這裡我研究了好一陣,堆上new的空間detach之後立刻delete沒問題
21         //防止記憶體洩漏,雖然一次8位元組,不過就是沒了指標,沒有直接管理執行緒的手段了,getID,nativeHandle等等
22         
23     }
24 
25 
26     
27 }
28 
29 ThreadPool::~ThreadPool()        //析構有好幾層析構,會比較慢
30 {
31     this->PoolAlive = false;        //唯一修改點,代表要回收執行緒池
32 
33     if(Controller->joinable())
34         Controller->join();            //把執行緒池管理者回收了,以確定全部執行緒被銷燬
35 
36 
37     delete Controller;
38     delete TaskQ;
39     
40 }

 

建構函式的一個要點:必須要先把一些東西都建立好了,再啟動執行緒,因為執行緒可能會訪問那些(尚未建立好)的元素

 

 1 //#include<stdio.h>
 2 //#define _CRT_SECURE_NO_WARNINGS
 3 #include<iostream>
 4 #include<map>
 5 #include<string>
 6 #include"ThreadPool.h"
 7 #include<Windows.h>
 8 using namespace std;
 9 
10 
11 void *test(void *arg) {
12     int a = (int)arg;
13     
14     for (int i = 2; i < a; ++i) {
15         Sleep(20);
16         
17         for (int j = 2; j <= i; j++) {
18             if (i%j == 0)
19                 cout << j << "\t";
20         }
21         cout << endl;
22     }
23     
24     return NULL;
25 
26 }
27 
28 
29 
30 
31 
32 
33 int main() {
34     
35     freopen("out.txt", "w", stdout);
36     ThreadPool MyPool(2,8);
37     MyPool.PushTask(test, (void*)10000);
38     Sleep(400);
39     MyPool.PushTask(test, (void*)10000);
40     MyPool.PushTask(test, (void*)10000);
41     Sleep(400);
42     MyPool.PushTask(test, (void*)10000);        //模擬不定時插入任務
43 
44 
45 
46 
47     Sleep(1000*2000);
48 
49     
50     return 0;
51 }

 

這個任務就是亂造的瞎寫些可整除數,防止太快,sleep(20)一會,正常跑起來了,CPU佔用率很低,因為有sleep(),"out.txt"增長速度一秒15k-20k吧,大致是正常跑起來了