为什么使用线程池
多线程通信优点之一便是cpu利用率高,响应速度快。对于单个服务器处理多个客户端任务时难免会对线程进行频繁的创建和销毁,这时引入池化技术便可以很好的解决这个问题,可以节省线程创建销毁时间开销的同时提高了线程复用性,减少线程间来回切换,从而减少cpu资源浪费。
线程池结构
以cs架构模型为例,用任务队列存储客户端链接任务,线程池从任务队列中拿取任务。
任务队列
struct job //创建任务类型
{
void * (*func)(void *arg); //函数指针,指向要执行的函数
void *arg; //函数的参数
struct job *next; //指向下一个任务的指针
};
线程池
struct threadpool //创建线程池
{
int thread_num; //线程数量
pthread_t *pthread_ids; //线程id
struct job *head; //任务队列头
struct job *tail; //任务队列尾
int queue_max_num; //任务 队列最大容量
int queue_cur_num; //队列已有任务数量
pthread_mutex_t mutex; //线程池访问队列资源锁
pthread_cond_t queue_full; //队列满
pthread_cond_t queue_not_empty; //队列不为空
pthread_cond_t queue_empty; //队列空
};
线程池中除了保存线程信息和指向任务队列头尾的指针之外还加入了互斥锁和若干条件变量。
mutex是一个互斥锁,可以保护任务队列资源,防止线程池中的多个线程同时访问任务队列导致的内容错乱,在一个线程访问时加锁不让其他线程访问。
条件变量queue_empty的作用是在队列中没有任务时阻塞线线程。
条件变量queue_not_empty在任务队列中被添加了任务时唤醒线程处理任务。