线程池原理及创建文档格式.docx
- 文档编号:8458079
- 上传时间:2023-05-11
- 格式:DOCX
- 页数:21
- 大小:23.87KB
线程池原理及创建文档格式.docx
《线程池原理及创建文档格式.docx》由会员分享,可在线阅读,更多相关《线程池原理及创建文档格式.docx(21页珍藏版)》请在冰点文库上搜索。
在任务执行完毕后线程也不退出,而是继续保持在池中等待下一次的任务。
当系统比较空闲时,大部分线程都一直处于暂停状态,线程池自动销毁一部分线程,回收系统资源。
基于这种预创建技术,线程池将线程创建和销毁本身所带来的开销分摊到了各个具体的任务上,执行次数越多,每个任务所分担到的线程本身开销则越小,不过我们另外可能需要考虑进去线程之间同步所带来的开销。
构建线程池框架
一般线程池都必须具备下面几个组成部分:
线程池管理器:
用于创建并管理线程池
工作线程:
线程池中实际执行的线程
任务接口:
尽管线程池大多数情况下是用来支持网络服务器,但是我们将线程执行的任务抽象出来,形成任务接口,从而是的线程池与具体的任务无关。
任务队列:
线程池的概念具体到实现则可能是队列,链表之类的数据结构,其中保存执行线程。
我们实现的通用线程池框架由五个重要部分组成CThreadManage,CThreadPool,CThread,CJob,CWorkerThread,除此之外框架中还包括线程同步使用的类CThreadMutex和CCondition。
CJob是所有的任务的基类,其提供一个接口Run,所有的任务类都必须从该类继承,同时实现Run方法。
该方法中实现具体的任务逻辑。
CThread是Linux中线程的包装,其封装了Linux线程最经常使用的属性和方法,它也是一个抽象类,是所有线程类的基类,具有一个接口Run。
CWorkerThread是实际被调度和执行的线程类,其从CThread继承而来,实现了CThread中的Run方法。
CThreadPool是线程池类,其负责保存线程,释放线程以及调度线程。
CThreadManage是线程池与用户的直接接口,其屏蔽了内部的具体实现。
CThreadMutex用于线程之间的互斥。
CCondition则是条件变量的封装,用于线程之间的同步。
它们的类的继承关系如下图所示:
线程池的时序很简单,如下图所示。
CThreadManage直接跟客户端打交道,其接受需要创建的线程初始个数,并接受客户端提交的任务。
这儿的任务是具体的非抽象的任务。
CThreadManage的内部实际上调用的都是CThreadPool的相关操作。
CThreadPool创建具体的线程,并把客户端提交的任务分发给CWorkerThread,CWorkerThread实际执行具体的任务。
理解系统组件
下面我们分开来了解系统中的各个组件。
CThreadManage
CThreadManage的功能非常简单,其提供最简单的方法,其类定义如下:
classCThreadManage
{
private:
CThreadPool*
m_Pool;
int
m_NumOfThread;
protected:
public:
void
SetParallelNum(intnum);
CThreadManage();
CThreadManage(intnum);
virtual~CThreadManage();
void
Run(CJob*job,void*jobdata);
TerminateAll(void);
};
其中m_Pool指向实际的线程池;
m_NumOfThread是初始创建时候允许创建的并发的线程个数。
另外Run和TerminateAll方法也非常简单,只是简单的调用CThreadPool的一些相关方法而已。
其具体的实现如下:
CThreadManage:
:
CThreadManage(){
m_NumOfThread=10;
m_Pool=newCThreadPool(m_NumOfThread);
}
CThreadManage(intnum){
m_NumOfThread=num;
~CThreadManage(){
if(NULL!
=m_Pool)
deletem_Pool;
voidCThreadManage:
SetParallelNum(intnum){
Run(CJob*job,void*jobdata){
m_Pool->
Run(job,jobdata);
TerminateAll(void){
TerminateAll();
CThread
CThread
类实现了对Linux中线程操作的封装,它是所有线程的基类,也是一个抽象类,提供了一个抽象接口Run,所有的CThread都必须实现该Run方法。
CThread的定义如下所示:
classCThread
m_ErrCode;
Semaphore
m_ThreadSemaphore;
//theinnersemaphore,whichisusedtorealize
unsigned
longm_ThreadID;
bool
m_Detach;
//Thethreadisdetached
m_CreateSuspended;
//ifsuspendaftercreating
char*
m_ThreadName;
ThreadStatem_ThreadState;
//thestateofthethread
SetErrcode(interrcode){m_ErrCode=errcode;
staticvoid*ThreadFunction(void*);
CThread();
CThread(boolcreatesuspended,booldetach);
virtual~CThread();
virtualvoidRun(void)=0;
SetThreadState(ThreadStatestate){m_ThreadState=state;
Terminate(void);
//Terminatethethrea
Start(void);
//Starttoexecutethethread
Exit(void);
Wakeup(void);
ThreadState
GetThreadState(void){returnm_ThreadState;
GetLastError(void){returnm_ErrCode;
SetThreadName(char*thrname){strcpy(m_ThreadName,thrname);
GetThreadName(void){returnm_ThreadName;
GetThreadID(void){returnm_ThreadID;
SetPriority(intpriority);
GetPriority(void);
GetConcurrency(void);
SetConcurrency(intnum);
Detach(void);
Join(void);
Yield(void);
Self(void);
线程的状态可以分为四种,空闲、忙碌、挂起、终止(包括正常退出和非正常退出)。
由于目前Linux线程库不支持挂起操作,因此,我们的此处的挂起操作类似于暂停。
如果线程创建后不想立即执行任务,那么我们可以将其“暂停”,如果需要运行,则唤醒。
有一点必须注意的是,一旦线程开始执行任务,将不能被挂起,其将一直执行任务至完毕。
线程类的相关操作均十分简单。
线程的执行入口是从Start()函数开始,其将调用函数ThreadFunction,ThreadFunction再调用实际的Run函数,执行实际的任务。
CThreadPool
CThreadPool是线程的承载容器,一般可以将其实现为堆栈、单向队列或者双向队列。
在我们的系统中我们使用STLVector对线程进行保存。
CThreadPool的实现代码如下:
classCThreadPool
friendclassCWorkerThread;
unsignedintm_MaxNum;
//themaxthreadnumthatcancreateatthesametime
unsignedintm_AvailLow;
//Theminnumofidlethreadthatshoulekept
unsignedintm_AvailHigh;
//Themaxnumofidlethreadthatkeptatthesametime
unsignedintm_AvailNum;
//thenormalthreadnumofidlenum;
unsignedintm_InitNum;
//Normalthreadnum;
CWorkerThread*GetIdleThread(void);
AppendToIdleList(CWorkerThread*jobthread);
MoveToBusyList(CWorkerThread*idlethread);
MoveToIdleList(CWorkerThread*busythread);
DeleteIdleThread(intnum);
CreateIdleThread(intnum);
CThreadMutexm_BusyMutex;
//whenvisitbusylist,usem_BusyMutextolockandunlock
CThreadMutexm_IdleMutex;
//whenvisitidlelist,usem_IdleMutextolockandunlock
CThreadMutexm_JobMutex;
//whenvisitjoblist,usem_JobMutextolockandunlock
CThreadMutexm_VarMutex;
CCondition
m_BusyCond;
//m_BusyCondisusedtosyncbusythreadlist
m_IdleCond;
//m_IdleCondisusedtosyncidlethreadlist
m_IdleJobCond;
//m_JobCondisusedtosyncjoblist
m_MaxNumCond;
vector<
CWorkerThread*>
m_ThreadList;
m_BusyList;
//ThreadList
m_IdleList;
//IdleList
CThreadPool();
CThreadPool(intinitnum);
virtual~CThreadPool();
SetMaxNum(intmaxnum){m_MaxNum=maxnum;
GetMaxNum(void){returnm_MaxNum;
SetAvailLowNum(intminnum){m_AvailLow=minnum;
GetAvailLowNum(void){returnm_AvailLow;
SetAvailHighNum(inthighnum){m_AvailHigh=highnum;
GetAvailHighNum(void){returnm_AvailHigh;
GetActualAvailNum(void){returnm_AvailNum;
GetAllNum(void){returnm_ThreadList.size();
GetBusyNum(void){returnm_BusyList.size();
SetInitNum(intinitnum){m_InitNum=initnum;
GetInitNum(void){returnm_InitNum;
CThreadPool:
CThreadPool()
m_MaxNum=50;
m_AvailLow=5;
m_InitNum=m_AvailNum=10;
m_AvailHigh=20;
m_BusyList.clear();
m_IdleList.clear();
for(inti=0;
i<
m_InitNum;
i++){
CWorkerThread*thr=newCWorkerThread();
thr->
SetThreadPool(this);
AppendToIdleList(thr);
Start();
}
CThreadPool(intinitnum)
assert(initnum>
0&
&
initnum<
=30);
m_MaxNum
=30;
m_AvailLow=initnum-10>
0?
initnum-10:
3;
m_InitNum=m_AvailNum=initnum;
m_AvailHigh=initnum+10;
//beginthethread,thethreadwaitforjob
~CThreadPool()
TerminateAll();
voidCThreadPool:
TerminateAll()
i<
m_ThreadList.size();
i++){
CWorkerThread*thr=m_ThreadList[i];
Join();
return;
CWorkerThread*CThreadPool:
GetIdleThread(void)
while(m_IdleList.size()==0)
m_IdleCond.Wait();
m_IdleMutex.Lock();
if(m_IdleList.size()>
0)
{
CWorkerThread*thr=(CWorkerThread*)m_IdleList.front();
printf("
GetIdlethread%dn"
thr->
GetThreadID());
m_IdleMutex.Unlock();
returnthr;
returnNULL;
//addanidlethreadtoidlelist
AppendToIdleList(CWorkerThread*jobthread)
m_IdleList.push_back(jobthread);
m_ThreadList.push_back(jobthread);
//moveandidlethreadtobusythread
MoveToBusyList(CWorkerThread*idlethread)
m_BusyMutex.Lock();
m_BusyList.push_back(idlethread);
m_AvailNum--;
m_BusyMutex.Unlock();
iteratorpos;
pos=find(m_IdleList.begin(),m_IdleList.end(),idlethread);
if(pos!
=m_IdleList.end())
m_IdleList.erase(pos);
MoveToIdleList(CWorkerThread*busythread)
m_IdleList.push_back(busythread);
m_AvailNum++;
pos=find(m_BusyList.begin(),m_BusyList.end(),busythread);
if(pos!
=m_BusyList.end())
m_BusyList.erase(pos);
m_IdleCond.Signal();
m_MaxNumCond.Signal();
//createnumidlethreadandputthemtoidlelist
CreateIdleThread(intnum)
num;
CWorkerThread*thr=ne
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 线程 原理 创建