线程池 ---构造,析构和声明 (附带一个测试main)
Posted slowman
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池 ---构造,析构和声明 (附带一个测试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吧,大致是正常跑起来了
以上是关于线程池 ---构造,析构和声明 (附带一个测试main)的主要内容,如果未能解决你的问题,请参考以下文章