一个简单的线程池
线程池
当我们需要多次使用线程时,需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。线程池是一种多线程处理形式,提前创建多个线程,处理过程中将任务添加到任务队列,每个线程不断往复的从任务队列中获取任务、执行任务。避免了在处理短时间任务时创建与销毁线程的代价。
应用场景:
1.需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。但对于长时间的任务,线程池的优点就不明显了。因为完成该任务时间可能比线程的创建时间大多了。
2.需要快速响应的需求。
3.突发性的大量需求,在没有线程池的情况下,将产生大量线程,而在短时间内产生大量线程可能会导致内存到达极限,出现错误。
在服务器使用一个线程来处理一个用户请求时,线程池可限制服务器中同时处理的用户数(等于线程池中线程总数)。
线程池示例:
1.创建固定数量线程的线程池,循环的从任务队列中获取任务对象;
2.获取到任务对象后,执行任务对象中的任务接口。
1 #ifndef __THREADPOOL_H_ 2 #define __THREADPOOL_H_ 3 4 #include <iostream> 5 #include <queue> 6 #include <pthread.h> 7 #include <unistd.h> 8 using namespace std; 9 10 typedef int (*hander) (int, int); 11 12 class Task 13 { 14 public: 15 int _x; 16 int _y; 17 hander _func; 18 public: 19 Task(const int& x, const int& y, hander func) 20 :_x(x) 21 ,_y(y) 22 ,_func(func) 23 {} 24 void Run() 25 { 26 cout << pthread_self() << " result: " << _func(_x, _y) << endl; 27 } 28 }; 29 30 class ThreadPool 31 { 32 private: 33 queue<Task> task_queue; //任务队列 34 size_t thread_count; 35 pthread_mutex_t mutex; //对任务队列的操作需保证线程安全 36 pthread_cond_t cond; //任务队列为空时阻塞线程,加入新任务时唤醒线程。 37 private: 38 void LockQueue() 39 { 40 pthread_mutex_lock(&mutex); 41 } 42 void UnLockQueue() 43 { 44 pthread_mutex_unlock(&mutex); 45 } 46 void BlockThread() 47 { 48 pthread_cond_wait(&cond, &mutex); 49 } 50 void SignalThread() 51 { 52 pthread_cond_signal(&cond); 53 } 54 Task GetTask() 55 { 56 Task t = task_queue.front(); 57 task_queue.pop(); 58 return t; 59 } 60 61 public: 62 ThreadPool(size_t count = 3) 63 :thread_count(count) 64 {} 65 static void *run_func(void *arg) //static函数没有参数this 66 { 67 ThreadPool *tp = (ThreadPool *)arg; //不能用this指针,使用参数传入一个对象指针,用来访问成员方法 68 while(1) //每个线程往复的拿任务,执行任务 69 { 70 tp->LockQueue(); 71 while(tp->task_queue.empty()) 72 { 73 tp->BlockThread(); //当前没有任务,线程被阻塞 74 } 75 //poptaskqueue 76 Task t = tp->GetTask(); 77 //unlockmutex 78 tp->UnLockQueue(); 79 //runtask 80 t.Run(); //在锁外执行任务 81 } 82 } 83 void InitThreadPool() 84 { 85 pthread_mutex_init(&mutex, NULL); 86 pthread_cond_init(&cond, NULL); 87 pthread_t tid; 88 while(thread_count--) 89 { 90 pthread_create(&tid, NULL, run_func, (void *)this); 91 } 92 } 93 void PutTask(const Task& t) 94 { 95 LockQueue(); 96 task_queue.push(t); 97 UnLockQueue(); 98 SignalThread(); //当有新任务时,唤醒可能被阻塞的线程 99 } 100 ~ThreadPool() 101 { 102 pthread_mutex_destroy(&mutex); 103 pthread_cond_destroy(&cond); 104 } 105 }; 106 107 class Singleton //单例 108 { 109 private: 110 static ThreadPool *tp; 111 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 112 public: 113 ThreadPool *GetInstance() 114 { 115 if(tp == NULL) 116 { 117 pthread_mutex_lock(&mutex); //为null时再加锁,避免当已经存在对象时仍需要等待获得锁 118 if(tp == NULL) //再次判断可避免在第一次判断和获得锁之间,有其他线程先一步为单例获得对象,而导致非单例 119 { 120 tp = new ThreadPool(5); 121 tp->InitThreadPool(); 122 } 123 pthread_mutex_unlock(&mutex); 124 } 125 return tp; 126 } 127 }; 128 129 ThreadPool *Singleton::tp = NULL; 130 131 #endif
1 #include "threadpool.hpp" 2 #include <cstdlib> 3 #include <ctime> 4 5 int Add(int x, int y) 6 { 7 return x + y; 8 } 9 int Sub(int x, int y) 10 { 11 return x - y; 12 } 13 int Mul(int x, int y) 14 { 15 return x * y; 16 } 17 int Div(int x, int y) 18 { 19 return x / y; 20 } 21 22 int main() 23 { 24 srand((unsigned int)time(NULL)); 25 hander func_arr[] = {Add, Sub, Mul, Div}; //模拟线程执行的任务 26 ThreadPool *tp = Singleton().GetInstance(); 27 while(1) 28 { 29 int x = rand() % 20 + 1; 30 int y = rand() % 5 + 1; 31 int index = rand() % 4; 32 Task t = Task(x, y, func_arr[index]); 33 cout << "Put task: " << x << " "<< index << " " << y << endl; 34 tp->PutTask(t); 35 sleep(1); 36 } 37 return 0; 38 }