C++ 线程池的封装实现
来源:互联网 发布:淘宝更改支付宝账号 编辑:程序博客网 时间:2024/05/17 00:08
为了充分利用多核的优势,我们利用多线程来进行任务处理,但线程也同样不能滥用,会带来一下几个问题:
1)线程本身存在开销,系统必须为每个线程分配如栈,TLS(线程局部存储),寄存器等。
2)线程管理会给系统带来开销,context切换同样会给系统带来成本。
3)线程本身是可以重用的资源,不需要每次都进行初始化。
所以往往在使用中,我们无需把线程与task任务进行一对一对应,只需要预先初始化有限的线程个数来处理无限的task任务即可,线程池应运而生,原理也就是如此。
线程池具体构造如下:
主要含有三个队列
- 工作队列
- 工作线程队列
- 忙碌线程队列
工作队列是一个阻塞队列,任务(仿函数)任务不算被push进来(notify阻塞获取的工作线程),工作线程队列(一直不变)则从该队列中获取任务执行(wait获取,当任务队列为空时阻塞等待通知),如果获取到任务,则将线程会进入忙碌线程队列中,执行任务的仿函数,当工作完成,重新移出工作线程队列。
定义线程池专属异常:
struct TC_ThreadPool_Exception : public TC_Exception
{
TC_ThreadPool_Exception(const string &buffer) : TC_Exception(buffer){};
TC_ThreadPool_Exception(const string &buffer, int err) : TC_Exception(buffer, err){};
~TC_ThreadPool_Exception () throw (){};
};
/**
* @brief 用通线程池类, 与tc_functor, tc_functorwrapper配合使用.
*
* 使用方式说明:
* 1 采用tc_functorwrapper封装一个调用
* 2 用tc_threadpool对调用进行执行
* 具体示例代码请参见:test/test_tc_thread_pool.cpp
*/
/**线程池本身继承自锁,可以帮助锁定**/
class TC_ThreadPool : public TC_ThreadLock
{
public:
/**
* @brief 构造函数
*
*/
TC_ThreadPool ();
/**
* @brief 析构, 会停止所有线程
*/
~TC_ThreadPool ();
/**
* @brief 初始化.
*
* @param num 工作线程个数
*/
void init(size_t num);
/**
* @brief 获取线程个数.
*
* @return size_t 线程个数
*/
size_t getThreadNum() { Lock sync(* this); return _jobthread. size(); }
/**
* @brief 获取线程池的任务数( exec添加进去的).
*
* @return size_t 线程池的任务数
*/
size_t getJobNum() { return _jobqueue. size(); }
/**
* @brief 停止所有线程
*/
void stop();
/**
* @brief 启动所有线程
*/
void start();
/**
* @brief 启动所有线程并, 执行初始化对象.
*
* @param ParentFunctor
* @param tf
*/
template<class ParentFunctor>
void start(const TC_FunctorWrapper< ParentFunctor> &tf)
{
for(size_t i = 0; i < _jobthread .size(); i++)
{
_startqueue. push_back(new TC_FunctorWrapper<ParentFunctor >(tf));
}
start();
}
/**
* @brief 添加对象到线程池执行,该函数马上返回,
* 线程池的线程执行对象
*/
template<class ParentFunctor>
void exec(const TC_FunctorWrapper< ParentFunctor> &tf)
{
_jobqueue.push_back(new TC_FunctorWrapper<ParentFunctor >(tf));
}
/**
* @brief 等待所有工作全部结束(队列无任务, 无空闲线程).
*
* @param millsecond 等待的时间( ms), -1:永远等待
* @return true, 所有工作都处理完毕
* false,超时退出
*/
bool waitForAllDone(int millsecond = -1);
public:
/**
* @brief 线程数据基类,所有线程的私有数据继承于该类
*/
class ThreadData
{
public:
/**
* @brief 构造
*/
ThreadData(){};
/**
* @brief 析够
*/
virtual ~ThreadData(){};
/**
* @brief 生成数据.
*
* @ param T
* @return ThreadData*
*/
template<typename T>
static T* makeThreadData()
{
return new T;
}
};
/**
* @brief 设置线程数据.
*
* @param p 线程数据
*/
static void setThreadData(ThreadData *p);
/**
* @brief 获取线程数据.
*
* @return ThreadData* 线程数据
*/
static ThreadData* getThreadData();
/**
* @brief 设置线程数据, key需要自己维护.
*
* @param pkey 线程私有数据key
* @param p 线程指针
*/
static void setThreadData(pthread_key_t pkey, ThreadData *p);
/**
* @brief 获取线程数据, key需要自己维护.
*
* @param pkey 线程私有数据key
* @return 指向线程的ThreadData*指针
*/
static ThreadData* getThreadData(pthread_key_t pkey);
protected:
/**
* @brief 释放资源.
*
* @param p
*/
static void destructor(void *p);
/**
* @brief 初始化key
*/
class KeyInitialize
{
public:
/**
* @brief 初始化key
*/
KeyInitialize()
{
int ret = pthread_key_create(&TC_ThreadPool::g_key, TC_ThreadPool::destructor);
if(ret != 0)
{
throw TC_ThreadPool_Exception("[TC_ThreadPool::KeyInitialize] pthread_key_create error", ret);
}
}
/**
* @brief 释放key
*/
~KeyInitialize()
{
pthread_key_delete(TC_ThreadPool::g_key);
}
};
/**
* @brief 初始化key的控制
*/
static KeyInitialize g_key_initialize;
/**
* @brief 数据key
*/
static pthread_key_t g_key;
protected:
/**
* @brief 线程池中的工作线程
*/
class ThreadWorker : public TC_Thread
{
public:
/**
* @brief 工作线程构造函数.
*
* @ param tpool
*/
ThreadWorker(TC_ThreadPool *tpool);
/**
* @brief 通知工作线程结束
*/
void terminate();
protected:
/**
* @brief 运行
*/
virtual void run();
protected:
/**
* 线程池指针
*/
TC_ThreadPool * _tpool;
/**
* 是否结束线程
*/
bool _bTerminate;
};
protected:
/**
* @brief 清除
*/
void clear();
/**
* @brief 获取任务, 如果没有任务, 则为NULL.
*
* @return TC_FunctorWrapperInterface*
*/
TC_FunctorWrapperInterface * get(ThreadWorker *ptw);
/**
* @brief 获取启动任务.
*
* @return TC_FunctorWrapperInterface*
*/
TC_FunctorWrapperInterface * get();
/**
* @brief 空闲了一个线程.
*
* @param ptw
*/
void idle(ThreadWorker *ptw);
/**
* @brief 通知等待在任务队列上的工作线程醒来
*/
void notifyT();
/**
* @brief 是否处理结束.
*
* @return bool
*/
bool finish();
/**
* @brief 线程退出时调用
*/
void exit();
friend class ThreadWorker;
protected:
/**
* 任务队列
*/
TC_ThreadQueue< TC_FunctorWrapperInterface*> _jobqueue;
/**
* 启动任务
*/
TC_ThreadQueue< TC_FunctorWrapperInterface*> _startqueue;
/**
* 工作线程
*/
std::vector<ThreadWorker *> _jobthread;
/**
* 繁忙线程
*/
std::set<ThreadWorker *> _busthread;
/**
* 任务队列的锁
*/
TC_ThreadLock _tmutex;
/**
* 是否所有任务都执行完毕
*/
bool _bAllDone;
};
工作线程设计如下:
TC_ThreadPool ::ThreadWorker::ThreadWorker(TC_ThreadPool *tpool)
: _tpool (tpool)
, _bTerminate ( false)
{
}
void TC_ThreadPool ::ThreadWorker::terminate()
{
_bTerminate = true;
_tpool->notifyT();
}
void TC_ThreadPool ::ThreadWorker::run()
{
//调用初始化部分
TC_FunctorWrapperInterface *pst = _tpool->get();
if(pst)
{
try
{
(*pst)();
}
catch ( ... )
{
}
delete pst;
pst = NULL;
}
//调用处理部分
while (! _bTerminate)
{
TC_FunctorWrapperInterface *pfw = _tpool->get( this);
if(pfw != NULL)
{
auto_ptr< TC_FunctorWrapperInterface> apfw(pfw);
try
{
(*pfw)();
}
catch ( ... )
{
}
_tpool->idle( this);
}
}
//结束
_tpool->exit();
}
每个工作线程在刚开始时都会执行一下初始化操作,并进入一个无限循环的部分//调用处理部分
while (! _bTerminate)
{
TC_FunctorWrapperInterface *pfw = _tpool->get( this);
if(pfw != NULL)
{
auto_ptr< TC_FunctorWrapperInterface> apfw(pfw);
try
{
(*pfw)();
}
catch ( ... )
{
}
_tpool->idle( this);
}
}
该工作主要是无限的从线程池的工作队列中获取任务并执行,如果成功获取任务,则会将线程移进忙碌队列:
TC_FunctorWrapperInterface *TC_ThreadPool:: get(ThreadWorker *ptw)
{
TC_FunctorWrapperInterface *pFunctorWrapper = NULL;
if(! _jobqueue. pop_front(pFunctorWrapper, 1000))
{
return NULL;
}
{
Lock sync( _tmutex);
_busthread. insert(ptw);
}
return pFunctorWrapper;
}
执行完,移回工作线程队列:_tpool->idle( this);
void TC_ThreadPool:: idle(ThreadWorker *ptw)
{
Lock sync( _tmutex);
_busthread. erase(ptw);
//无繁忙线程, 通知等待在线程池结束的线程醒过来
if( _busthread. empty())
{
_bAllDone = true;
_tmutex.notifyAll();
}
}
此处jobThread队列初始化后不会改变(因为没有实现自增长功能),所以非线程安全的vector队列即可,busthread的忙碌线程队列会被移进移出,但是操作会自带Lock sync( _tmutex),该互斥量是线程池本身继承的,所以是共有的,也无需另外使用线程安全的TC_ThreadQueue,使用vector即可。
TC_ThreadPool:: idle中的
if( _busthread. empty())
{
_bAllDone = true;
_tmutex.notifyAll();
}
主要用于当线程池工作起来后的waitForAllDone方法:
bool TC_ThreadPool:: waitForAllDone( int millsecond)
{
Lock sync( _tmutex);
start1:
//任务队列和繁忙线程都是空的
if (finish())
{
return true;
}
//永远等待
if(millsecond < 0)
{
_tmutex.timedWait(1000);
goto start1;
}
int64_t iNow = TC_Common:: now2ms();
int m = millsecond;
start2:
bool b = _tmutex.timedWait(millsecond);
//完成处理了
if(finish())
{
return true;
}
if(!b)
{
return false;
}
millsecond = max((int64_t )0, m - (TC_Common ::now2ms() - iNow));
goto start2;
return false;
}
_tmutex.timedWait(millsecond)方法唤醒。反复判断是否所有的工作是否完成:
bool TC_ThreadPool:: finish()
{
return _startqueue. empty() && _jobqueue .empty() && _busthread. empty() && _bAllDone;
}
整体cpp实现如下:
TC_ThreadPool ::KeyInitialize TC_ThreadPool::g_key_initialize;
pthread_key_t TC_ThreadPool::g_key ;
void TC_ThreadPool::destructor( void *p)
{
ThreadData *ttd = ( ThreadData*)p;
if(ttd)
{
delete ttd;
}
}
void TC_ThreadPool::exit()
{
TC_ThreadPool:: ThreadData *p = getThreadData();
if(p)
{
delete p;
int ret = pthread_setspecific( g_key, NULL );
if(ret != 0)
{
throw TC_ThreadPool_Exception ("[TC_ThreadPool::setThreadData] pthread_setspecific error", ret);
}
}
_jobqueue. clear();
}
void TC_ThreadPool::setThreadData( TC_ThreadPool:: ThreadData *p)
{
TC_ThreadPool:: ThreadData *pOld = getThreadData();
if(pOld != NULL && pOld != p)
{
delete pOld;
}
int ret = pthread_setspecific( g_key, ( void *)p);
if(ret != 0)
{
throw TC_ThreadPool_Exception ("[TC_ThreadPool::setThreadData] pthread_setspecific error", ret);
}
}
TC_ThreadPool ::ThreadData * TC_ThreadPool::getThreadData ()
{
return ( ThreadData *) pthread_getspecific( g_key);
}
void TC_ThreadPool::setThreadData( pthread_key_t pkey, ThreadData *p)
{
TC_ThreadPool:: ThreadData *pOld = getThreadData(pkey);
if(pOld != NULL && pOld != p)
{
delete pOld;
}
int ret = pthread_setspecific(pkey, ( void *)p);
if(ret != 0)
{
throw TC_ThreadPool_Exception ("[TC_ThreadPool::setThreadData] pthread_setspecific error", ret);
}
}
TC_ThreadPool ::ThreadData * TC_ThreadPool::getThreadData( pthread_key_t pkey)
{
return ( ThreadData *) pthread_getspecific(pkey);
}
TC_ThreadPool::TC_ThreadPool()
: _bAllDone ( true)
{
}
TC_ThreadPool::~TC_ThreadPool()
{
stop();
clear();
}
void TC_ThreadPool::clear()
{
std::vector< ThreadWorker *>::iterator it = _jobthread. begin();
while(it != _jobthread. end())
{
delete (*it);
++it;
}
_jobthread. clear();
_busthread. clear();
}
void TC_ThreadPool::init( size_t num)
{
stop();
Lock sync(* this);
clear();
for( size_t i = 0; i < num; i++)
{
_jobthread. push_back( new ThreadWorker( this));
}
}
void TC_ThreadPool::stop()
{
Lock sync(* this);
std::vector< ThreadWorker *>::iterator it = _jobthread. begin();
while(it != _jobthread. end())
{
if ((*it)-> isAlive())
{
(*it)-> terminate();
(*it)-> getThreadControl().join ();
}
++it;
}
_bAllDone = true;
}
void TC_ThreadPool::start()
{
Lock sync(* this);
std::vector< ThreadWorker *>::iterator it = _jobthread. begin();
while(it != _jobthread. end())
{
(*it)-> start();
++it;
}
_bAllDone = false;
}
bool TC_ThreadPool:: finish()
{
return _startqueue. empty() && _jobqueue .empty() && _busthread. empty() && _bAllDone;
}
bool TC_ThreadPool::waitForAllDone( int millsecond)
{
Lock sync( _tmutex);
start1:
//任务队列和繁忙线程都是空的
if (finish ())
{
return true;
}
//永远等待
if(millsecond < 0)
{
_tmutex.timedWait(1000);
goto start1;
}
int64_t iNow = TC_Common:: now2ms();
int m = millsecond;
start2:
bool b = _tmutex.timedWait(millsecond);
//完成处理了
if(finish ())
{
return true;
}
if(!b)
{
return false;
}
millsecond = max((int64_t )0, m - (TC_Common ::now2ms() - iNow));
goto start2;
return false;
}
TC_FunctorWrapperInterface *TC_ThreadPool::get( ThreadWorker *ptw)
{
TC_FunctorWrapperInterface *pFunctorWrapper = NULL;
if(! _jobqueue. pop_front(pFunctorWrapper, 1000))
{
return NULL;
}
{
Lock sync( _tmutex);
_busthread. insert(ptw);
}
return pFunctorWrapper;
}
TC_FunctorWrapperInterface *TC_ThreadPool::get()
{
TC_FunctorWrapperInterface *pFunctorWrapper = NULL;
if(! _startqueue. pop_front(pFunctorWrapper))
{
return NULL;
}
return pFunctorWrapper;
}
void TC_ThreadPool::idle( ThreadWorker *ptw)
{
Lock sync( _tmutex);
_busthread. erase(ptw);
//无繁忙线程, 通知等待在线程池结束的线程醒过来
if( _busthread. empty())
{
_bAllDone = true;
_tmutex.notifyAll();
}
}
void TC_ThreadPool::notifyT()
{
_jobqueue. notifyT();
}
原文地址:http://blog.csdn.net/turkeyzhou/article/details/8755976
0 0
- 使用QueueUserWorkerItem实现的线程池封装
- C++ 线程池的封装实现
- 使用QueueUserWorkerItem实现的线程池封装
- C++ 线程池的封装实现
- C++ 线程池的封装实现
- C++ 线程池的封装实现
- 使用QueueUserWorkerItem实现的线程池封装
- C++ 线程池的封装实现
- 一个通用简单线程池实现的初步封装(C语言)
- C实现-CPP的-封装
- Linux线程池C++封装实现
- linux线程池的C语言实现
- linux线程池的C语言实现
- linux线程池的C语言实现
- linux线程池的C语言实现
- Linux下C线程池的实现
- linux线程池的C语言实现
- 简单Linux C线程池的实现
- Linux批量杀死进程的几种方式
- AWS China Region试用的问题列表
- oracle 转mysql
- 给eclipse安装SVN插件
- 用例
- C++ 线程池的封装实现
- javascript——用户代理(环境)检测
- CentOS下SVN服务的启动与关闭
- 在linux上使用yum安装 和 卸载 JDK
- 广告自动轮播(完美解决人为滑动后按顺序自动轮播)
- VS开发问题:应用程序无法启动 因为程序的并行配置不正确 ,解决方案
- 淘宝DruidDataSource配置使用--一发
- 探索并发编程(一)------操作系统篇
- Linux添加crontab定时任务