您的位置:首页 > 编程语言 > C语言/C++

[C++][线程池][完整实现] 转:线程池原理及创建(C++实现)

2017-01-09 19:14 411 查看
文章的主要框架是参考这篇文档的,http://jacky-dai.iteye.com/blog/1090285,

关于作者 

张中庆,西安交通大学软件所,在读硕士,目前研究方向为分布式网络与移动中间件,对Linux极其爱好,可以通过flydish1234@sina.com.cn与我联系

其实看了好多类似的,都是没有完整的实现,自己花了点时间把这个程序梳理了一下,写了个测试程序,目前可以跑通。

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <assert.h>
#include <Windows.h>
#include <functional>
#include <process.h>

using namespace std;
class CThread;

//锁的基类
class CLockObject
{
public:
virtual BOOL Lock() = 0;
virtual BOOL UnLock() = 0;
};

//任务基类,所有要执行的任务都继承这个类
class CJob
{
private:
int m_JobNo;//任务ID 用来调试是否绑定特定线程
char* m_JobName; //任务名字,用来调试是否绑定特定线程
CThread* m_pWorkThread; //The thread associated with the job
public:
CJob();
virtual ~CJob();
CThread *GetWorkThread(void); //获取工作线程
void SetWorkThread(CThread* pWorkThread);//设置工作线程
virtual void Execute(void* ptr) = 0; //执行函数
int GetJobNo(void) const { return m_JobNo; }
void SetJobNo(int jobno){ m_JobNo = jobno;}
char* GetJobName(void) const { return m_JobName; }
void SetJobName(char* jobname);
};

void CJob::SetJobName(char* jobname)
{
if(NULL !=m_JobName)
{
free(m_JobName);
m_JobName = NULL;
}

if(NULL !=jobname)
{
m_JobName = (char*)malloc(strlen(jobname)+1);
strcpy(m_JobName,jobname);
}
}

CThread* CJob::GetWorkThread(void)
{
return m_pWorkThread;
}

void CJob::SetWorkThread(CThread *pWorkThread)
{
m_pWorkThread = pWorkThread;
}

CJob::CJob(void) :m_pWorkThread(NULL),m_JobName(NULL), m_JobNo(0)
{

}

CJob::~CJob()
{
if (NULL != m_JobName)
{
free(m_JobName);
m_JobName = NULL;
}
}

//线程状态
typedef enum _ThreadState
{
THREAD_RUNNING = 0x0, //运行
THREAD_IDLE = 0x1,//空闲
THREAD_EXIT = 0X2,//退出
}ThreadState;

//线程基类
class CThread
{
private:
int m_ErrorCode; //错误码
unsigned long m_ThreadID; //线程ID
char* m_ThreadName; //线程名字
ThreadState m_ThreadState; //线程状态
HANDLE m_hthreadHandle; //线程句柄
bool m_IsExit;//是否退出
protected:
static unsigned __stdcall ThreadFunction(void*); //start调用此函数,此函数再调用run函数,执行实际的任务
public:
CThread();
virtual ~CThread();

virtual void Run() = 0;

//设置线程状态
void SetThreadState(ThreadState state);
//获取线程状态
ThreadState GetThreadState();

//Start to execute the thread
bool Start();

//获取线程ID
int GetThreadID(void);

//设置错误码
void SetErrorCode(int errorCode);
//获取错误码
int GetLastError(void);

//设置线程名字
void SetThreadName(char* threadName);
//获取线程名字
char* GetThreadName();

//设置线程优先级
bool SetPriority(int priority);
//获取线程优先级
int GetPriority(void);

bool Terminate(void);
HANDLE GetThreadHandle();
void SetThreadHandle(HANDLE hdl);
void SetExitFlag(bool bExit);
bool GetExitFlag();
bool NeedExit();
};

bool CThread::NeedExit()
{
return m_IsExit;
}

void CThread::SetExitFlag(bool bExit)
{
m_IsExit = bExit;
}

bool CThread::GetExitFlag()
{
return m_IsExit;
}

bool CThread::Terminate(void)
{
_endthreadex(0);
return TRUE;
}

HANDLE CThread::GetThreadHandle()
{
return m_hthreadHandle;
}

void CThread::SetThreadHandle(HANDLE hdl)
{
m_hthreadHandle = hdl;
}

void CThread::SetErrorCode(int errorCode)
{
m_ErrorCode = errorCode;
}

int CThread::GetLastError(void)
{
return m_ErrorCode;
}

CThread::CThread()
{
m_IsExit = FALSE;
}

CThread::~CThread()
{

}

void CThread::SetThreadState(ThreadState state)
{
m_ThreadState = state;
}

ThreadState CThread::GetThreadState()
{
return m_ThreadState;
}

//Start to execute the thread
bool CThread::Start()
{
unsigned threadID;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, this, 0, &threadID);
this->m_ThreadID = threadID;
this->SetThreadHandle(hThread);
return true;
}

unsigned __stdcall CThread::ThreadFunction(void* pArg)
{
CThread* pThread = (CThread*)pArg;
pThread->Run();
return TRUE;
}

int CThread::GetThreadID(void)
{
return m_ThreadID;
}

void CThread::SetThreadName(char* threadName)
{
strncpy(m_ThreadName, threadName, strlen(threadName));
}

char* CThread::GetThreadName()
{
return m_ThreadName;
}

//线程互斥锁
class CThreadMutex: public CLockObject
{
private:
CRITICAL_SECTION m_CritSec;//临界区
public:
CThreadMutex();
~CThreadMutex();
BOOL Lock();//加锁,阻塞式
BOOL UnLock();//解锁
BOOL TryLock();//加锁,非阻塞式
};

CThreadMutex::CThreadMutex()
{
#if (_WIN32_WINNT >= 0x0403)
//使用 InitializeCriticalSectionAndSpinCount 可以提高性能
::InitializeCriticalSectionAndSpinCount(&m_CritSec,4000);
#else
::InitializeCriticalSection(&m_CritSec);
#endif
}

CThreadMutex::~CThreadMutex()
{
::DeleteCriticalSection(&m_CritSec);
}

BOOL CThreadMutex::Lock()
{
::EnterCriticalSection(&m_CritSec);
return TRUE;
}

BOOL CThreadMutex::UnLock()
{
::LeaveCriticalSection(&m_CritSec);
return TRUE;
}

BOOL CThreadMutex::TryLock()
{
BOOL bRet = TryEnterCriticalSection(&m_CritSec);
return bRet;
}

//条件变量
class CThreadCondition
{
private:
HANDLE m_phEvent; //句柄
public:
CThreadCondition();
~CThreadCondition();
void Wait();
void Signal();
};

CThreadCondition::CThreadCondition()
{
//第二个参数 bManualReset FALSE the system automatically resets the state to nonsignaled
//If this parameter is TRUE, the function creates a manual-reset event object
//第三个参数 bInitialState FALSE it is nonsignaled
m_phEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
}

CThreadCondition::~CThreadCondition()
{
if (NULL != m_phEvent)
{
::CloseHandle((m_phEvent));
}
}

void CThreadCondition::Wait()
{
//If dwMilliseconds is INFINITE, the function will return only when the object is signaled.
WaitForSingleObject(m_phEvent, INFINITE);
ResetEvent(m_phEvent);
}

void CThreadCondition::Signal()
{
//Sets the specified event object to the signaled state
SetEvent(m_phEvent);
}

//线程池类,主要负责调度线程,创建线程,删除线程
class CThreadPool
{
friend class CWorkerThread;
private:
unsigned int m_nMaxNum; //当前线程池中所允许并发存在的线程的最大数目
unsigned int m_nAvailLow; //当前线程池中所允许存在的空闲线程的最小数目
//如果空闲数目低于该值,表明负载可能过重,此时有必要增加空闲线程池的数目
//实现中我们总是将线程调整为m_InitNum个
unsigned int m_nAvailHigh;//当前线程池中所允许的空闲的线程的最大数目,
//如果空闲数目高于该值,表明当前负载可能较轻,此时将删除多余的空闲线程,删除后调整数也为m_InitNum个
unsigned int m_nCurIdleThreadsNum;//当前线程池中实际存在的线程的个数,其值介于m_nAvailHigh和m_nAvailLow之间
//如果线程的个数始终维持在m_nAvailLow和m_nAvailHigh之间,则线程既不需要创建,也不需要删除,保持平衡状态
unsigned int m_nInitThreadsNum;//初始创建时线程池中的线程的个数

protected:
CWorkerThread* GetIdleThread(void);//获取空闲线程
void AppendToIdleList(CWorkerThread* jobthread);//线程加入空闲队列
void MoveToBusyList(CWorkerThread* idlethread);//线程加入忙碌队列
void MoveToIdleList(CWorkerThread* busythread);//线程加入空闲队列
void DeleteIdleThread(int num); //删除空闲线程
void CreateIdleThread(int num); //创建空闲线程

public:
CThreadMutex m_BusyMutex;//when visit busy list,use m_BusyMutex to Lock and unlock
CThreadMutex m_IdleMutex;//when visit idle list,use m_IdleMutex to Lock and unlock
CThreadMutex m_ThreadNumMutex;//变量锁, 目前用在m_nCurIdleThreadsNum修改上面

CThreadCondition m_BusyCond; //m_BusyCond is used to sync busy thread list
CThreadCondition m_IdleCond; //m_IdleCond is used to sync idle thread list
CThreadCondition m_MaxNumCond;//m_MaxNumCond is used to sync m_nCurIdleThreadsNum

vector<CWorkerThread*> m_vecAllThreads;//所有创建出来的线程集合
vector<CWorkerThread*> m_vecBusyThreads;//忙碌线程队列,随着负载的多少会改变
vector<CWorkerThread*> m_vecIdleThreads;//空闲线程队列,随着负的多少会改变

public:
void SetMaxNum(int maxnum){m_nMaxNum = maxnum;} //设置线程池运行的最大线程数
int GetMaxNum(void){return m_nMaxNum;}
void SetAvailLowNum(int minnum){m_nAvailLow = minnum;} //设置最少空闲线程数
int GetAvailLowNum(void){return m_nAvailLow;}
void SetAvailHighNum(int highnum){m_nAvailHigh = highnum;} //设置最多空闲线程数
int GetAvailHighNum(void){return m_nAvailHigh;}
int GetCurIdleThreadsNum(void){return m_nCurIdleThreadsNum;} //获取当前空闲线程个数
int GetAllThreadsNum(void){return m_vecAllThreads.size();} //获取所有线程个数
int GetBusyThreadsNum(void){return m_vecBusyThreads.size();} //获取忙碌空闲线程个数
void SetInitNum(int initnum){m_nInitThreadsNum = initnum;}
int GetInitNum(void){return m_nInitThreadsNum;}
CThreadPool();
~CThreadPool();
CThreadPool(int initnum);
void TerminateAll();
void Run(CJob* job,void* jobdata);
};

//真正的工作线程,执行操作的线程
class CWorkerThread : public CThread
{
private:
CThreadPool* m_pThreadPool;//线程池
CJob* m_pJob;//任务
void* m_pJobData;//任务参数
CThreadMutex m_VarMutex;//
public:
CThreadCondition m_JobAddCond; //有新的任务时触发条件变量,每个线程一个条件变量,可以指定线程去执行任务
CThreadMutex m_WorkMutex;//
CWorkerThread();
virtual ~CWorkerThread();
void Run();
void AddNewJob(CJob* job,void* jobdata);
CJob* GetJob(void){return m_pJob;}
void SetThreadPool(CThreadPool* thrpool);
CThreadPool* GetThreadPool(void){return m_pThreadPool;}
void Terminate(void);
};

void CWorkerThread::Terminate(void)
{
//工作线程再处理任务结束才会解锁,这个时候再去退出线程,避免打断线程处理任务。
m_WorkMutex.Lock();
SetExitFlag(TRUE);
//工作为假 代表要求线程退出
m_pJob = NULL;
m_pJobData = NULL;
printf("thread [%d] ready to exit\n", GetThreadID());
m_JobAddCond.Signal();
m_WorkMutex.UnLock();
WaitForSingleObject(GetThreadHandle(), INFINITE);
CloseHandle(GetThreadHandle());
}

CWorkerThread::CWorkerThread()
{
m_pJobData = NULL;
m_pJob = NULL;
m_pThreadPool = NULL;
}

CWorkerThread::~CWorkerThread()
{
if (NULL != m_pJob) {delete m_pJob; m_pJob = NULL;}
if (NULL != m_pThreadPool) {delete m_pThreadPool; m_pThreadPool = NULL;}
}

void CWorkerThread::Run()
{
printf("Enter CWorkerThread::Run\n");
SetThreadState(THREAD_RUNNING);
for(;;)
{
//当前线程不退出才需要等待任务的到来
while ((NULL == m_pJob) && !NeedExit())
{
printf("thread [%d] wait for job \n", GetThreadID());
m_JobAddCond.Wait();
}

if (NULL == m_pJob)
{
printf("thread [%d] exitFlag [%d]\n", GetThreadID(), NeedExit());
if (NeedExit())
{
break;//不再等待任务,退出线程
}
else
{
//任务为NULL 但不是线程退出,跳过这个任务
printf("m_pJob [%p] exitFlag [%d]\n", m_pJob, NeedExit());
continue;
}
}

m_WorkMutex.Lock();
printf("thread [%d] accept the job [%d]\n", GetThreadID(), m_pJob->GetJobNo());
//真正执行任务的地方
m_pJob->Execute(m_pJobData);
m_pJob->SetWorkThread(NULL);
m_pJob = NULL;
m_pJobData = NULL;
m_pThreadPool->MoveToIdleList(this);
SetThreadState(THREAD_IDLE);
if(m_pThreadPool->m_vecIdleThreads.size() > m_pThreadPool->GetAvailHighNum())
{
m_pThreadPool->DeleteIdleThread(m_pThreadPool->m_vecIdleThreads.size() - m_pThreadPool->GetInitNum());
}
m_WorkMutex.UnLock();
}
printf("thread [%d] exit\n", GetThreadID());
}

void CWorkerThread::AddNewJob(CJob* pJob,void* jobdata)
{
assert(NULL != pJob);
m_VarMutex.Lock();
m_pJob = pJob;
m_pJobData = jobdata;
pJob->SetWorkThread(this);
m_VarMutex.UnLock();
printf("job [%d] add to the pool\n",m_pJob->GetJobNo());
m_JobAddCond.Signal();
}

void CWorkerThread::SetThreadPool(CThreadPool* thrpool)
{
m_VarMutex.Lock();
m_pThreadPool = thrpool;
m_VarMutex.UnLock();
}

CThreadPool::CThreadPool()
{
m_nMaxNum = 50;
m_nAvailLow = 5;
m_nInitThreadsNum = 10;
m_nCurIdleThreadsNum = 10;
m_nAvailHigh = 20;
m_vecBusyThreads.clear();
m_vecIdleThreads.clear();
int i;
for (i=0; i<m_nInitThreadsNum; ++i)
{
CWorkerThread* pNewWorkThread = new CWorkerThread;
pNewWorkThread->SetThreadPool(this);
AppendToIdleList(pNewWorkThread);
pNewWorkThread->Start();
}
}

CThreadPool::CThreadPool(int initnum)
{
m_nMaxNum = 30;
m_nAvailLow = (initnum-10>0)?(initnum-10):3;
m_nInitThreadsNum = m_nCurIdleThreadsNum = initnum ;
m_nAvailHigh = initnum+10;
m_vecAllThreads.clear();
m_vecBusyThreads.clear();
m_vecIdleThreads.clear();
int i;
for (i=0; i<m_nInitThreadsNum; ++i)
{
CWorkerThread* pNewWorkThread = new CWorkerThread;
pNewWorkThread->SetThreadPool(this);
AppendToIdleList(pNewWorkThread);
pNewWorkThread->Start();
}
printf("CThreadPool::CThreadPool: Create Thread [%d] success\n", m_nInitThreadsNum);
}

CThreadPool::~CThreadPool()
{
TerminateAll();
}

void CThreadPool::TerminateAll()
{
int i;
for (i=0; i<m_vecAllThreads.size(); ++i)
{
CWorkerThread* pWorkThread = m_vecAllThreads[i];
pWorkThread->Terminate();
}
}

//获取空闲的线程
CWorkerThread* CThreadPool::GetIdleThread(void)
{
while (0 == m_vecIdleThreads.size())
{
printf("no idle threads, must wait\n");
m_IdleCond.Wait();
}
m_IdleMutex.Lock();
if (0 < m_vecIdleThreads.size())
{
CWorkerThread* pIdleThread = (CWorkerThread*)m_vecIdleThreads.front();
printf("get idle thread %d \n", pIdleThread->GetThreadID());
m_IdleMutex.UnLock();
return pIdleThread;
}
m_IdleMutex.UnLock();
printf("warning: no idle threads return\n");
return NULL;
}

//add an idle thread to idle list
void CThreadPool::AppendToIdleList(CWorkerThread* jobthread)
{
m_IdleMutex.Lock();
m_vecIdleThreads.push_back(jobthread);
m_vecAllThreads.push_back(jobthread);
m_IdleMutex.UnLock();
}

//move and idle thread to busy thread
void CThreadPool::MoveToBusyList(CWorkerThread* idlethread)
{
m_BusyMutex.Lock();
m_vecBusyThreads.push_back(idlethread);
m_nCurIdleThreadsNum--;
m_BusyMutex.UnLock();

m_IdleMutex.Lock();
vector<CWorkerThread*>::iterator pos;
pos = find(m_vecIdleThreads.begin(),m_vecIdleThreads.end(),idlethread);
if(pos != m_vecIdleThreads.end())
{
m_vecIdleThreads.erase(pos);
}
m_IdleMutex.UnLock();
}

void CThreadPool::MoveToIdleList(CWorkerThread* busythread)
{
m_IdleMutex.Lock();
m_vecIdleThreads.push_back(busythread);
m_nCurIdleThreadsNum++;
m_IdleMutex.UnLock();

m_BusyMutex.Lock();
vector<CWorkerThread*>::iterator pos;
pos = find(m_vecBusyThreads.begin(),m_vecBusyThreads.end(),busythread);
if(pos!=m_vecBusyThreads.end())
m_vecBusyThreads.erase(pos);
m_BusyMutex.UnLock();
m_IdleCond.Signal();
m_MaxNumCond.Signal();
}

//create num idle thread and put them to idlelist
void CThreadPool::CreateIdleThread(int num)
{
int i;
for (i=0;i<num;i++)
{
CWorkerThread* pWorkThread = new CWorkerThread();
pWorkThread->SetThreadPool(this);
AppendToIdleList(pWorkThread);
m_ThreadNumMutex.Lock();
m_nCurIdleThreadsNum++;
m_ThreadNumMutex.UnLock();
pWorkThread->Start();//begin the thread,the thread wait for job
}
}

void CThreadPool::DeleteIdleThread(int num)
{
printf("Enter into CThreadPool::DeleteIdleThread\n");
m_IdleMutex.Lock();
printf("Delete Num is %dn",num);
int i;
for(i=0;i<num;i++)
{
CWorkerThread* thr;
if(m_vecIdleThreads.size() > 0 )
{
thr = (CWorkerThread*)m_vecIdleThreads.front();
printf("Get Idle thread %dn",thr->GetThreadID());
}
else
{
printf("no idle thread, no need to delete thread\n");
break;
}

vector<CWorkerThread*>::iterator pos;
pos = find(m_vecIdleThreads.begin(),m_vecIdleThreads.end(),thr);
if(pos!=m_vecIdleThreads.end())
m_vecIdleThreads.erase(pos);
m_nCurIdleThreadsNum--;
printf("The idle thread available num:%d n",m_nCurIdleThreadsNum);
printf("The idlelist num:%d n",m_vecIdleThreads.size());
}
m_IdleMutex.UnLock();
}

void CThreadPool::Run(CJob* job, void* jobdata)
{
assert(NULL != job);
//if the busy thread num adds to m_nMaxNum,so we should wait
if(m_nMaxNum <= GetBusyThreadsNum())
{
printf("busy threads beyond the max threads number in the pool, must wait for idle threads\n");
m_MaxNumCond.Wait();
}

//负载过重,空闲线程少,需要创建新的线程, 使其数目达到m_InitNum
if(m_vecIdleThreads.size() < m_nAvailLow)
{
if(GetAllThreadsNum()+m_nInitThreadsNum-m_vecIdleThreads.size() < m_nMaxNum )
{
//当前有m_vecIdleThreads.size()空闲线程, 另外再创建m_nInitThreadsNum - m_vecIdleThreads.size(), 当前总的空闲线程为m_nInitThreadsNum
CreateIdleThread(m_nInitThreadsNum - m_vecIdleThreads.size());
}
else
{
CreateIdleThread(m_nMaxNum - GetAllThreadsNum());
}
}

CWorkerThread* pWorkthread = GetIdleThread();
if(NULL != pWorkthread)
{
pWorkthread->m_WorkMutex.Lock();
MoveToBusyList(pWorkthread);
pWorkthread->SetThreadPool(this);
job->SetWorkThread(pWorkthread);
printf("Job [%d] bind to thread [%d] \n", job->GetJobNo(), pWorkthread->GetThreadID());
pWorkthread->AddNewJob(job, jobdata);
pWorkthread->m_WorkMutex.UnLock();
}
else
{
printf("impossible to going here\n");
}
}

//线程管理类
class CThreadManage
{
public:
CThreadManage();
CThreadManage(int num);
virtual ~CThreadManage();
void Run(CJob* pjob, void* pJobData);//运行任务
void TerminateAll(); //停止所有的线程
private:
int m_nNumOfThread; //初始时允许创建的最大的线程个数
CThreadPool* m_pPool;//实际的线程池
};

CThreadManage::CThreadManage()
{
m_nNumOfThread = 10;
m_pPool = new CThreadPool(m_nNumOfThread);
}

CThreadManage::CThreadManage(int num)
{
m_nNumOfThread = num;
m_pPool = new CThreadPool(m_nNumOfThread);
}

CThreadManage::~CThreadManage()
{
if (NULL != m_pPool)
{
delete m_pPool;
m_pPool = NULL;
}
}

void CThreadManage::Run(CJob* pjob, void* pJobData)
{
m_pPool->Run(pjob, pJobData);
}

void CThreadManage::TerminateAll()
{
m_pPool->TerminateAll();
}

class myjob : public CJob
{
public:
myjob(){}
myjob(int i){SetJobNo(i);}
~myjob(){}
void Execute(void* jobdata) {
printf("The Job comes from CXJOB\n");
::Sleep(2);
}
};

#if 0
int main()
{
CThreadManage* manage = new CThreadManage(50);
for(int i=0;i<1000;i++)
{
myjob* job = new myjob(i);
manage->Run(job, NULL);
}
::Sleep(2);

myjob* job = new myjob();
manage->Run(job, NULL);
manage->TerminateAll();
return 0;
}
#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: