线程池 ---构造,析构和声明 (附带一个测试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)的主要内容,如果未能解决你的问题,请参考以下文章

mysql基本数据类型,附带学习经验

多测师讲解性能测试_____Tomcat调优的方法_____高级讲师肖sir

线程池设置最多M线程执行N个任务

C++11线程池库及测试demo

分析线程池源码测试线程池

006-多线程-JUC线程池-并发测试程序