理解线程池存在的意义
如果有多个用户多次而频繁的请求操作,服务器上每次就会创建一个线程为该用户的该次操作提供服务,若每个任务的执行时间也很短,那么创建线程和销毁线程所用事件占总共时长的比重就会增大。为了出现这种情况得到优化,因此,线程池出现了。
线程池的实现
- 得首先创建一些线程。
- 得有一个队列,线程得从这个队列中获取需要执行的任务。
- 要封装存在队列中的任务,提供好用的接口。
所需头文件
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <queue>
using namespace std;
设计任务类
需求
- 可以通过固定接口传递用户需要执行的任务。
- 提供接口可以让用户传递所需要执行的数据。
- 提供接口让用户可以重置所需要执行的任务。
- 任务执行接口直接写在该类中,线程只需要调用接口就可以,减少了线程池代码量。
代码实现
//typedef一个函数指针
typedef void (*TaskHandler)(int data);
class ThreadTask
{
private:
int _data;//任务参数
TaskHandler _handler;//任务
public:
ThreadTask(int data,TaskHandler handler):_data(data),_handler(handler)
{}
ThreadTask(){}
//任务重置接口
bool TaskSet(int data,TaskHandler handler)
{
_data = data;
_handler = handler;
return true;
}
//任务执行接口
bool TaskRun()
{
_handler(_data);
return true;
}
};
设计线程池类
需求
- 不能直接在构造函数中创建线程,不然发生错误无法返回信息。
- 得有队列,直接使用stl里面现成的就好。
- 提供添加任务接口。
- 提供一个互斥锁和一个条件变量,避免多个线程对同一个任务的争抢。
代码实现
#define MAX_THR 4
class ThreadPool
{
private:
std::queue<ThreadTask> task_queue;
int thr_num;
pthread_mutex_t _mutex;
pthread_cond_t _cond_con;
pthread_cond_t _cond_pro;
public:
//以下这几个函数,只是提供接口供静态函数调用私有成员
void ThreadLock()
{
pthread_mutex_lock(&_mutex);
}
void ThreadUnlock()
{
pthread_mutex_unlock(&_mutex);
}
bool QueueEmpty()
{
return task_queue.empty();
}
void ThreadWait()
{
pthread_cond_wait(&_cond_con,&_mutex);
}
bool QueuePop(ThreadTask &tt)
{
tt = task_queue.front();
task_queue.pop();
return true;
}
private:
//必须设置为静态函数,因为如果是成员函数,参数中有this指针,不符合接口
static void *thr_start(void *arg)
{
ThreadPool* pool = (ThreadPool*)arg;
while(1)
{
pool->ThreadLock();
while(pool->QueueEmpty())
{
pool->ThreadWait();
}
ThreadTask tt;
pool->QueuePop(tt);
pool->ThreadUnlock();
tt.TaskRun();
}
return NULL;
}
public:
ThreadPool(int max = MAX_THR):thr_num(max)
{}
//设置初始化接口的原因是,构造函数无法获取返回值,若创建线程失败我们则无从得知。
//1.创建线程
//2.初始化互斥锁和条件变量
bool PoolInit()
{
pthread_t tid[MAX_THR];
pthread_mutex_init(&_mutex,NULL);
pthread_cond_init(&_cond_con,NULL);
pthread_cond_init(&_cond_pro,NULL);
for(int i = 0; i<thr_num;i++)
{
int ret = pthread_create(&tid[i],NULL,thr_start,(void*)this);
if(ret!=0)
{
printf("create error\n");
return false;
}
pthread_detach(tid[i]);
}
return true;
}
//设置插入接口的目的是为了让用户插入所需要处理的代码
bool TaskPush(ThreadTask &tt)
{
pthread_mutex_lock(&_mutex);
task_queue.push(tt);
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_con);
return true;
}
};
测试
设置一个函数,用来输出一串关于参数的信息,放进线程池中多次执行。
设置测试函数
void test(int data)
{
printf("this is %p --get data:%d \n",pthread_self(),data);
sleep(1);//睡眠一秒,方便查看
}
主函数调用
int main()
{
ThreadPool pool;
//初始化线程池
pool.PoolInit();
//预期打印出十行数据
for(int i = 0;i<10 ;i++)
{
ThreadTask task(i,test);
pool.TaskPush(task);
}
while(1)
{
sleep(1);
}
return 0;
}