这篇文章谈到了:
为什么要使用线程池?线程的一些缺陷不足
线程池的构造?通过图形象的说明。三个队列:工作队列,工作线程队列,忙碌线程队列
还有附有实例代码。
所以是一个入门的概念性了解的好文。
---------------------------------------------------------------------------------
为了充分利用多核的优势,我们利用多线程来进行任务处理,但线程也同样不能滥用,会带来一下几个问题:
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();
}