线程池和线程池版本的服务器代码 Linux网络通信

线程池介绍线程池: 一种线程使用模式 。线程过多会带来调度开销,进而影响缓存局部性和整体性能 。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务 。这避免了在处理短时间任务时创建与销毁线程的代价 。线程池不仅能够保证内核的充分利用,还能防止过分调度 。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量
线程池的价值:

  1. 需要大量的线程来完成任务,且完成任务的时间比较短 。可同时处理多任务,多请求 。
  2. 有任务可以立即从线程池中调取线程取处理 , 节省了线程创建的时间
  3. 有效防止服务端线程过多而导致系统过载的问题
实现线程池中首先需要有很多个线程,用户可以自己选择创建多少个线程 。为了实现线程间的同步与互斥 , 还需要增加两个变量——互斥量和条件变量 。我们还需要一个任务队列,主线程不断往里面塞任务 , 线程池的线程不断去处理 。需要注意的是:这里的任务队列可以为空 , 但不能满 , 所以任务队列的容量不限定(实际场景中,任务队列容量不够就需要考虑换一台更大的服务器)
线程池的四个成员变量:
  • 一个队列: 存放任务
  • 线程池中线程数: 记录线程池中创建的线程数
  • 互斥量: 一个互斥锁
  • 条件变量: 两个条件变量
【线程池和线程池版本的服务器代码 Linux网络通信】
线程池和线程池版本的服务器代码 Linux网络通信

文章插图
线程池:首先需要创建几个线程,还有一个任务队列,当任务队列有任务的时候就唤醒一个正在等待的线程,让线程去执行任务,线程池中的线程执行完任务不会销毁,大大减少的cpu的消耗 。
需要两个条件变量和一个互斥锁 , 这个互斥锁用来锁住任务队列 , 因为任务队列是公共资源,其次还需要两个条件变量,一个条件变量用来阻塞取任务的线程,当队列中有任务的时候,直接取任务,然后解锁,当任务队列中没有任务的时候,解锁等待条件,条件满足抢锁 , 取任务 , 解锁 。另一个条件变量用来阻塞添加者进程,当任务队列满了,会让添加者进程等待,当有线程取走一个任务的时候,会唤醒添加者进程 。
版本一任务函数
这里的任务函数采用的时回调函数的方式,提高了代码的通用性 , 可以根据自己的需求改写任务函数
//任务回调函数void taskRun(void *arg){PoolTask *task = (PoolTask*)arg;int num = task->tasknum;printf("task %d is runing %lu\n",num,pthread_self());sleep(1);printf("task %d is done %lu\n",num,pthread_self());}线程池的主要代码框架
class ThreadPool{public://构造函数,初始化线程池ThreadPool(int thrnum, int maxtasknum){}static void* thrRun(void* arg){}//析构函数,摧毁线程池~ThreadPool(){}public://添加任务到线程池void addtask(){};private://任务队列相关的参数int max_job_num;//最大任务个数int job_num;//实际任务个数PoolTask *tasks;//任务队列数组int job_push;//入队位置int job_pop;// 出队位置//线程相关参数int thr_num;//线程池内线程个数pthread_t *threads;//线程池内线程数组int shutdown;//是否关闭线程池pthread_mutex_t pool_lock;//线程池的锁pthread_cond_t empty_task;//任务队列为空的条件pthread_cond_t not_empty_task;//任务队列不为空的条件};放任务: 主线程无脑往任务队列中塞任务,塞任务之前进行加锁,塞完任务解锁,如果任务队列已经满了,等待线程取任务,然后唤醒在条件变量下等待的队列;放入了任务就给线程发送信号,唤醒线程来取取任务: 线程池中的线程从任务队列中取任务,需要对任务队列上锁,因为对公共资源的操作都需要上锁,如果没有任务就阻塞,等待放任务唤醒;如果取完了一个任务,就唤醒添加任务
这就是两个条件变量和一个互斥锁的用法
//添加任务到线程池void addtask(){pthread_mutex_lock(&(this->pool_lock));//实际任务总数大于最大任务个数则阻塞等待(等待任务被处理)while(this->max_job_num <= this->job_num){pthread_cond_wait(&(this->empty_task),&(this->pool_lock));}int taskpos = (this->job_push++)%this->max_job_num;this->tasks[taskpos].tasknum = beginnum++;this->tasks[taskpos].arg = (void*)&this->tasks[taskpos];this->tasks[taskpos].task_func = taskRun;this->job_num++;pthread_mutex_unlock(&(this->pool_lock));pthread_cond_signal(&(this->not_empty_task));//通知包身工}

推荐阅读