什么是线程池?
所谓线程池,顾名思义就是一个关于线程的数据结构;线程池是由服务器预先创建的一组子线程,线程池中的线程数量应该和CPU数量差不多。线程池中的所有子线程都运行着相同的代码。当有新的任务到来的时候,主线程将通过某种方式选择线程池的某一个子线程来为之服务。
选择方式
1.主线程使用某种算法主动选择子线程。最简单又最常用的算法是随机算法和Round Robin(轮流选取)算法
2.主线程和所有子线程通过一个共享的工作队列来同步,子线程都睡眠在该工作队列上。当有新的任务到来的时候,主线程将任务添加到工作队列中。这将唤醒正在等待任务的子线程,不过只有一个子线程可以拿到任务的“接管权”,其他子线程只能继续睡眠等待有新的任务的到来
为什么要用线程池,创建线程池的好处是什么?
首先我们知道,线程是系统调度执行的最小单位,虽然是最小的,但是每次的创建线程或者销毁线程都需要浪费CPU资源,那样的服务器在每次有一个任务到来的时候都通过创建一个新的子线程来处理任务,处理完后就销毁,会浪费很多的CPU资源,所以我们设想预先创建好一些进程,每次有任务到来的时候就唤醒其中一个线程区执行任务,其他线程继续等待,执行完任务的线程并不会销毁,而是睡眠。这样就避免了CPU资源的大量浪费,因为线程已经被创建好了,需要的时候直接拿出来用,不需要转到内核态再去创建,不需要的时候也可以直接睡眠。
线程池里的线程数量应该是多少?
我们创建线程池的时候不要创建过多的线程,如果创建太多线程,就体现不出线程池的优势了,但是也不能之创建1,2个线程,那样没办法处理高并发的连接,那么线程池里面的线程数量应该是多少呢?
线程数量
1.线程数量与CPU,IO,并行,并发这些因素都有关
2.CPU密集型应用:CPU的数目+1
3.IO密集型应用:2*CPU的数目+1
4.最佳线程数目=(线程等待时间与线程CPU时间之比+1)*CPU数目
如何设计一个线程池呢?
线程池有点类似生产者-消费者模型,每次生产者生产出产品(即客户端发来请求任务),都会通知消费者去消费(子线程进行请求任务的处理)
设计步骤
1.设置一个生产者消费者队列,作为临界资源(全局资源)
2.初始化n个线程,并让其运行起来,加锁去队列里面取任务进行处理
3.如果任务队列为空的话,线程就阻塞
4.当生产者队列有一个任务后,就先对队列加锁,然后使用条件变量去通知阻塞队列中的一个线程来处理
线程同步机制封装类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| #include <iostream> using namespace std; #include <pthread.h>
class Locker() { public: Locker() { pthread_mutex_init(&mutex,null); } void Lock() { pthread_mutex_lock(&mutex); } void Unlock() { pthread_mutex_unlock(&mutex); } ~Locker() { pthread_mutex_destroy(&mutex); } private: pthread_mutex_t mutex; };
class Cond { public: Cond() { pthread_cond_intit(&cond,null); } ~Cond() { pthread_cond_destroy(&cond); } void Wait(othread_mutex_t *mutex) { pthread_cond_wait(&cond,mutex); } void Signal() { pthread_cond_signal(&cond); } private: pthread_cond_t cond; };
class Sem { public: Sem(int num) { sem_init(&sem,0,num); } ~Sem() { sem_destroy(&sem); } void Wait() { sem_wait(&sem); } void Post() { sem_post(&sem); } private: sem_t sem; };
|
线程池代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| #include "lock.h" #include <queue.h> #include <exception>
template <class T> class pthread_pool { public: pthread_pool(int num=8,int max_queue=1000); ~pthread_pool(); bool Append(); private: static void *worker(void *arg); void run(); private: int m_num; pthread_t *m_pthread; int m_max_queue; queue<T *> q; Lock lock; Sem sem; bool stop; };
template <class T> pthread_pool<T>::pthread_pool(int num,int max_queue):m_num(num),m_max_queue(max_queue),stop(false),m_pthread(NULL) { if((num<=0)||(max_queue<=0)) { throw std::exception(); } m_pthread=new pthread_t[num]; for(int i=0;i<num;i++) { pthread_create(m_pthread+i,NULL,worker,this); pthread_detach(m_pthread[i]); } }
template<class T> pthread_pool<T>::~pthread_pool() { delete []m_pthread; stop=true; }
template<class T> bool pthread_pool::Append(T* request) { lock.Lock(); if(q.size()>m_max_queue) { lock.Unlock(); return false; } q.push_back(requset); lock.Unlock(); sem.Post(); return true; }
template<class> void pthread_pool<T>::worker(void *arg) { pthread_pool *pool=(pthread_pool *)arg; pool->run(); }
template<class> void pthread_pool<T>::run() { while(!stop) { sem.Wait(); lock.Lock(); T* request=q.front(); q.pop(); lock.Unlock(); } request->process(); }
|
emmmmm,以上就是我对线程池的理解咯,欢迎各位大佬指教呀!