线程池的设计大致需要包含这几部分:
线程请求队列(存放业务请求)、
工作线程(进行业务处理)、
线程同步模块(互斥量、信号量)
以及操作请求队列的接口(append)。
下面代码封装了一个简易的线程池,采用模板类进行实现
template<class T>
class threadpool
{
public:
//max_requests 请求队列中最多允许的、等待处理的请求的数量
threadpool(Pool* connPool, int threadnum = 8, int max_request = 10000);
~threadpool();
bool append_p(T* request); //将事件放入请求队列
private:
//工作线程函数, 不断从工作队列里面取任务
static void* worker(void* arg); //取任务, 调用run
void run(); //执行任务
private:
int m_thread_number; //线程池大小
int m_max_requests; //请求队列中允许的最大请求数量
pthread_t* m_threads; //线程变量数组
std::list<T*> m_workqueue; //请求队列
locker m_queuelocker; //保护请求队列
sem m_queuestat; //请求队列中的请求数信号量
Pool* m_connPool; //数据库连接
};
具体实现:
template<class T>
threadpool<T>::threadpool(Pool* connPool, int threadnum, int max_request)
:m_connPool(connPool), m_thread_number(threadnum),
m_max_requests(max_request),m_threads(nullptr)
{
if(threadnum <= 0 || max_request <= 0){
throw std::exception();
}
m_threads = new pthread_t[m_thread_number]; //创建线程变量
if(m_threads == nullptr){
throw std::exception();
}
//接下来建立线程池
for(int i = 0; i < m_thread_number; ++i){
if(pthread_create(m_threads + i, NULL, worker, this) != 0){
delete []m_threads;
throw std::exception();
}
if(pthread_detach(m_threads[i]) != 0){
//使用detach分离线程, 该线程结束后资源自动回收, 无需join
delete []m_threads;
throw std::exception();
}
}
}
template<class T>
threadpool<T>::~threadpool(){
//销毁线程池
delete []m_threads;
}
template<class T>
bool threadpool<T>::append_p(T* request){
m_queuelocker.lock();
if(m_workqueue.size() >= m_max_requests){
//请求队列已满
m_queuelocker.unlock();
return false;
}
m_workqueue.push_back(request); //将请求放入请求队列
m_queuelocker.unlock();
m_queuestat.post(); //信号量+1
return true;
}
template<class T>
void* threadpool<T>::worker(void* arg){
threadpool* pool = (threadpool*)arg;
pool->run(); //执行任务
return pool;
}
template<class T>
void threadpool<T>::run(){
while(true){
m_queuestat.wait(); //如果无请求需要处理,阻塞在这里
m_queuelocker.lock();
if(m_workqueue.empty()){
//没有任务可处理
m_queuelocker.unlock();
continue;
}
T* request = m_workqueue.front(); //取任务
m_workqueue.pop_front();
m_queuelocker.unlock(); //下面不再操作共享任务队列, 解锁
//下面就是进行业务的处理,可根据实际需求进行填补
}
同步机制实现:
class locker
{
public:
locker(){
if(pthread_mutex_init(&mtx, nullptr) != 0){
throw std::exception();
}
}
~locker(){
pthread_mutex_destroy(&mtx);
}
bool lock(){
return pthread_mutex_lock(&mtx) == 0;
}
bool unlock(){
return pthread_mutex_unlock(&mtx) == 0;
}
pthread_mutex_t* GetMtx(){ //获取一把锁
return &mtx;
}
private:
pthread_mutex_t mtx;
};
class sem
{
public:
sem(int num){
if(sem_init(&id, 0, num) != 0){ //线程共享
throw std::exception();
}
}
sem(){
if(sem_init(&id, 0, 0) != 0){
throw std::exception();
}
}
~sem(){
sem_destroy(&id);
}
bool wait(){
return sem_wait(&id) == 0;
}
bool post(){
return sem_post(&id) == 0;
}
private:
sem_t id;
};