记linux下对线程池的学习及使用(二)--对线程池类的封装
结合了条件量,互斥量,任务基类,任务链表,这里对线程池类进行了完整的封装,并且在底部附上了线程池的一个简易测试案例。下面是封装源码
phreadpool.h
#ifndef _PTHREADPOOL_H
#define _PTHREADPOOL_H
#include <list>
#include <iostream>
#include<unistd.h>
#include "PThreadCond.h"
#include "PThreadMutex.h"
#include "Task.h"
using namespace std;
class CPThreadPool
{
public:
CPThreadPool(int max = 20,int min = 3,int waitsec = 60);
~CPThreadPool();
static void *TaskThread(void *arg);
void AddTask(CTask *task);
void start();
void destory();
void CreateThread();
private:
bool m_stop;
int m_maxcount;
int m_mincount;
int m_waitcount;
int m_curcount;
int m_waitsec;
CPThreadCond m_cond;
CPThreadCond m_taskMutex;
list<CTask *> m_tasklist;
};
#endif
pthreadpool.cpp
构造函数
CPThreadPool::CPThreadPool(int max,int min,int waitsec)
{
this->m_stop = false;
this->m_maxcount = max;
this->m_mincount = min;
this->m_waitcount = 0;
this->m_curcount = 0;
this->m_waitsec = waitsec;
}
用m_waitcount记录休眠线程数,用m_curcount记录当前总线程数;
m_maxcount记录最大线程数,m_mincount记录最小线程数;
m_waitsec记录单个线程最大等待时间
析构函数
CThreadPool::~CThreadPool()
{
destroy();
}
destroy函数
void CPThreadPool::destory()
{
m_stop = true;
while(m_curcount > 0)
{
m_cond.lock();
m_cond.broadcast();
m_cond.unlock();
sleep(1);
}
}
任务添加函数
void CPThreadPool::AddTask(CTask *task)
{
printf("addtask\n");
if(this->m_stop)
{
return;
}
m_taskMutex.lock();
m_tasklist.push_back(task);
m_taskMutex.unlock();
m_cond.lock();
if(m_waitcount)
{
m_cond.signal();
}
else if(m_curcount < m_maxcount)
{
CreateThread();
}
m_cond.unlock();
}
这里互斥量taskMutex的作用是保证多个被唤醒的线程在竞争tasklist任务链表时同步。
创建线程函数
void CPThreadPool::CreateThread()
{
pthread_t tid;
int ret = pthread_create(&tid,NULL,TaskThread,(void *)this);
if(ret < 0)
{
perror("pthread create");
}
else
{
m_curcount++;
}
}
start函数
void CThreadPool::start()
{
m_cond.lock();
m_bStop = false;
m_cond.unlock();
}
工作主线程
// Work thread
void *CPThreadPool::TaskThread(void *arg)
{
pthread_detach(pthread_self());
CPThreadPool *pool = (CPThreadPool*)arg;
while(1)
{
pool->m_cond.lock();
if(pool->m_tasklist.empty())
{
if(pool->m_stop)
{
pool->m_curcount--;
pool->m_cond.unlock();
pthread_exit(NULL);
}
pool->m_waitcount++;
bool bsignal = pool->m_cond.timewait(pool->m_waitsec);
pool->m_waitcount--;
if(!bsignal && pool->m_curcount > pool->m_mincount)
{
pool->m_curcount--;
pool->m_cond.unlock();
pthread_exit(NULL);
}
}
pool->m_cond.unlock();
pool->m_taskMutex.lock();
if(!pool->m_tasklist.empty())
{
CTask *t = pool->m_tasklist.front();
pool->m_tasklist.pop_front();
pool->m_taskMutex.unlock();
t->run();
delete t;
}
else
{
pool->m_taskMutex.unlock();
}
}
}
对线程池封装的简易测试
#include<iostream>
#include"./PThreadPool.h"
using namespace std;
class CMytask:public CTask
{
public:
CMytask(int id){m_id = id;}
~CMytask(){}
int run()
{
printf("run id is %d\n",m_id);
sleep(1);
return 0;
}
int m_id;
};
int main(int argc,char *argv[])
{
CPThreadPool pool(100,3,60);
int i = 0;
for(i = 0;i<5000;i++)
{
CMytask *task = new CMytask(i);
pool.AddTask(task);
}
sleep(10);
return 0;
}
测试结果
结果分析
由以上测试结果分析可以得知,线程池在封装完成后,调度起来十分的方便。在这里我只是新建了一个cmytask类用于打印数字i
class CMytask:public CTask
{
public:
CMytask(int id){m_id = id;}
~CMytask(){}
int run()
{
printf("run id is %d\n",m_id);
sleep(1);
return 0;
}
int m_id;
};
所有的打印过程都通过addtask这个接口送到线程池中即可。
for(i = 0;i<5000;i++)
{
CMytask *task = new CMytask(i);
pool.AddTask(task);
}