執行緒池 (4)---構造,析構和宣告 (附帶一個測試main)
阿新 • • 發佈:2018-12-04
先上程式碼,宣告部分
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> 1415 #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 3233 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吧,大致是正常跑起來了