昨天晚上写了一个线程池管理,记录下来吧:
//@author: tigermei
//@data: 2012/03/20
//thread base
#ifndef THREADBASE_H_
#define THREADBASE_H_
//
//macro that is used to prevet copy and assign the object
#define DISALLOW_COPY_AND_ASSIGN(ClassName) \
ClassName(const ClassName&); \
void operator=(const ClassName&)
class CThreadBase
{
public:
CThreadBase();
virtual ~CThreadBase();
//
//start the the thread
BOOL Start();
//
//wait the thread the times of dwElapseTime until the thread is destroyed
//@dwElapseTime the times that is needed to wait
BOOL Wait(DWORD dwElapseTime = INFINITE);
//
//get the handle of the thread
HANDLE GetHandle(){ return m_hThreadHandle; }
protected:
//
//the function that is needed to be extended
//it is pure virtual functin, the work thread will call it
virtual int Run() = 0;
private:
//
//the start of the work thread
static unsigned int __stdcall start_address(void * param);
DISALLOW_COPY_AND_ASSIGN(CThreadBase);
private:
//
//handle of the new work thread
HANDLE m_hThreadHandle;
//
//the id of the new work thread
DWORD m_dwThreadId;
};
#endif
//@author: tigermei
//@data: 2012/03/20
//thread base
#include "stdafx.h"
#include "ThreadBase.h"
#include <assert.h>
#include <process.h>
CThreadBase::CThreadBase(): m_hThreadHandle(INVALID_HANDLE_VALUE), m_dwThreadId(0)
{
}
CThreadBase::~CThreadBase()
{
if(m_hThreadHandle != INVALID_HANDLE_VALUE)
::CloseHandle(m_hThreadHandle);
}
BOOL CThreadBase::Start()
{
if(m_hThreadHandle != INVALID_HANDLE_VALUE)
{
assert(false);
return FALSE;
}
//
//start a new work thread
m_hThreadHandle = (HANDLE)_beginthreadex(0, 0,
start_address, (void *)this, 0, (unsigned int *)&m_dwThreadId);
return m_hThreadHandle != INVALID_HANDLE_VALUE;
}
unsigned int __stdcall CThreadBase::start_address( void * param)
{
CThreadBase *pThread = (CThreadBase *)param;
if(pThread)
{
return pThread->Run();
}
return 0;
}
BOOL CThreadBase::Wait(DWORD dwElapseTime)
{
DWORD dwWaitResult = ::WaitForSingleObject(m_hThreadHandle, dwElapseTime);
if(dwWaitResult == WAIT_OBJECT_0)
return TRUE;
else
return FALSE;
return FALSE;
}
//@author: tigermei
//@data: 2012/03/20
//Worker thread
#ifndef TASK_H
#define TASK_H_
#include "ThreadBase.h"
#include "Lock.h"
#include <queue>
#include <vector>
#define EVENT_NUM 2
class Request;
class CWorkersMgr;
extern const int NumberOfThreads;
//
//the class CWorker is used to pack the work thread
//
class CWorker : public CThreadBase
{
public:
//
//@param pWorkerMgr we need some variables frome the
// object of CWorkersMgr
CWorker(CWorkersMgr *pWorkerMgr);
virtual ~CWorker();
//
//when we need stop the current thread ,call the function stop
BOOL Stop();
protected:
//
//this function will be called in the worker thread
virtual int Run();
private:
//
//do the real work
void WorkerThread();
private:
CWorkersMgr *m_pWorkerMgr;
//
//m_hHanleEvent[0] quit event, when we need stop the thread, we signal the event
//m_hHanleEvent[1] the same as the member of m_hRequestSemaphore in CWorkersMgr
HANDLE m_hHanleEvent[EVENT_NUM];
};
//
//class CWorkersMgr manage the request queue
//and manage the work threads
//
class CWorkersMgr
{
public:
CWorkersMgr();
~CWorkersMgr();
//
//Get the request from the queue, we need lock here
//@return the request in the queue, when we return the request
// we also need remove it from the queue
//
Request *GetNextRequest();
//
//if there is some requestes, we push it into the queue
//@param pRequest the pointor of the request
//
void PushRequest(Request *pRequest);
//
//tell if the request queue is empty
//
BOOL IsRequestQueueEmpty();
//
//create work thread
//
void CreateWorkers();
//wait until the work has been completed
//
void WaitUntilWorkComplete();
//
//destroy the work thread and some member variables
//
void DestroyWorkers();
private:
void Uninit();
public:
//m_hRequestSemaphore is used to resume the work thread to process the request
HANDLE m_hRequestSemaphore;
//when the request has be completed, m_hRequestComplete will be signaled
HANDLE m_hRequestComplete;
//Synchronous different threads to process the task queue
CLock m_csQueueAccess;
private:
//Request queue
std::queue<Request *> m_queueRequest;
//work thread
std::vector<CWorker *> m_arrayWorkers;
};
#endif
//@author: tigermei
//@data: 2012/03/20
//Worker thread
#include "stdafx.h"
#include <assert.h>
#include "Work.h"
#include "ThreadBase.h"
extern const int NumberOfThreads;
extern Request * GetRequest() throw();
extern void ProcessRequest(Request * request) throw();
#define TRY_WAIT_TIMES 3
CWorker::CWorker(CWorkersMgr *pWorkerMgr)
{
m_pWorkerMgr = pWorkerMgr;
m_hHanleEvent[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
if(m_pWorkerMgr)
{
m_hHanleEvent[1] = m_pWorkerMgr->m_hRequestSemaphore;
}
}
CWorker::~CWorker()
{
if(m_hHanleEvent[0])
::CloseHandle(m_hHanleEvent[0]);
if(m_hHanleEvent[1])
m_hHanleEvent[1] = NULL;
}
int CWorker::Run()
{
WorkerThread();
return 0;
}
void CWorker::WorkerThread()
{
//loop here
for(;;)
{
//
//we wait two events here
//one is the request event, the other is quit event
DWORD dwRet = WaitForMultipleObjects(EVENT_NUM, m_hHanleEvent, FALSE, INFINITE);
if(dwRet == WAIT_OBJECT_0)
{
//
//the quit event has been signaled
break;
}
else if(dwRet == WAIT_OBJECT_0 +1)
{
//
//there are request that needed be processed
Request *request = m_pWorkerMgr->GetNextRequest();
ProcessRequest(request);
delete request;
//
//check if there are more request
//if there is no requestes in the queue,we need signal the complete event
if(m_pWorkerMgr->IsRequestQueueEmpty())
{
::SetEvent(m_pWorkerMgr->m_hRequestComplete);
}
}
else
{
assert(false);
break;
}
}
}
BOOL CWorker::Stop()
{
//
//signal the quit event so that the worker thread can jump out frome the loop
::SetEvent(m_hHanleEvent[0]);
return Wait(20);
}
/CWorkersMgr//
CWorkersMgr::CWorkersMgr()
{
m_hRequestSemaphore = INVALID_HANDLE_VALUE;
m_hRequestComplete = INVALID_HANDLE_VALUE;
}
CWorkersMgr::~CWorkersMgr()
{
m_hRequestSemaphore = INVALID_HANDLE_VALUE;
m_hRequestComplete = INVALID_HANDLE_VALUE;
}
void CWorkersMgr::CreateWorkers()
{
m_hRequestSemaphore = ::CreateSemaphore(NULL, 0, 0xff, NULL);
m_hRequestComplete = ::CreateEvent(NULL, FALSE, TRUE, NULL);
CWorker *pWorkersArray = new CWorker(this);
for(int i = 0; i < NumberOfThreads ; ++i)
{
CWorker *pWorkers = new CWorker(this);
m_arrayWorkers.push_back(pWorkers);
//
//we need start the thread, if there are no request
//the work thread will wait the request event
pWorkers->Start();
}
}
void CWorkersMgr::WaitUntilWorkComplete()
{
WaitForSingleObject(m_hRequestComplete, INFINITE);
}
void CWorkersMgr::DestroyWorkers()
{
int nWorkers = m_arrayWorkers.size();
for(int i = 0 ; i < nWorkers ; ++i)
{
//
//stop the worker thread
BOOL bStop = m_arrayWorkers[i]->Stop();
if(!bStop)
{
//
//if not stop, we TRY_WAIT_TIMES times to wait
//500ms every time
for(int j = 0; j < TRY_WAIT_TIMES; ++j)
{
bStop = m_arrayWorkers[i]->Wait(500);
if(bStop) break;
}
//
//After TRY_WAIT_TIMES times try
//the thread still doesn't stop ,we terminate it
if(!bStop)
{
::TerminateThread(m_arrayWorkers[i]->GetHandle(), 0);
}
}
}
//
//uninit other variables
Uninit();
}
void CWorkersMgr::Uninit()
{
::CloseHandle(m_hRequestSemaphore);
::CloseHandle(m_hRequestComplete);
int nWorkers = m_arrayWorkers.size();
for(int i = 0 ; i < nWorkers ; ++i)
{
CWorker *pWorker = m_arrayWorkers[i];
delete pWorker;
}
while(!m_queueRequest.empty())
{
Request *request = m_queueRequest.front();
m_queueRequest.pop();
delete request;
}
}
Request *CWorkersMgr::GetNextRequest()
{
CAutoLock autoLock(&m_csQueueAccess);
Request *request = m_queueRequest.front();
m_queueRequest.pop();
return request;
}
void CWorkersMgr::PushRequest(Request *pRequest)
{
if(pRequest)
{
//
//the request queue is shared by main thread and worker threads
CAutoLock autoLock(&m_csQueueAccess);
m_queueRequest.push(pRequest);
//
//when there are requestes, we must set the complete event no signal
::ResetEvent(m_hRequestComplete);
//
//add the request semaphore
ReleaseSemaphore(m_hRequestSemaphore, 1, NULL);
}
}
BOOL CWorkersMgr::IsRequestQueueEmpty()
{
CAutoLock autoLock(&m_csQueueAccess);
return m_queueRequest.empty();
}
//@author: tigermei
//@data: 2012/03/20
//Lock
#ifndef LOCK_H_
#define LOCK_H_
class CAutoLock;
class CLock
{
public:
CLock();
~CLock();
void Enter();
void Leave();
private:
CRITICAL_SECTION m_CritSect;
};
//
// use example:
//
// CLock lock;
// {
// CAutoLock autoLock(&lock);
// }
//
class CAutoLock
{
public:
CAutoLock(CLock *pLock);
~CAutoLock();
private:
CLock *m_pLock;
};
#endif
//@author: tigermei
//@data: 2012/03/20
//Lock
#include "stdafx.h"
#include "Lock.h"
CLock::CLock()
{
::InitializeCriticalSection(&m_CritSect);
}
CLock::~CLock()
{
::DeleteCriticalSection(&m_CritSect);
}
void CLock::Enter()
{
::EnterCriticalSection(&m_CritSect);
}
void CLock::Leave()
{
::LeaveCriticalSection(&m_CritSect);
}
CAutoLock::CAutoLock(CLock *pLock)
{
m_pLock = pLock;
//
//Enter the lock
if(m_pLock)
m_pLock->Enter();
}
CAutoLock::~CAutoLock()
{
//
//Leave the lock
if(m_pLock)
m_pLock->Leave();
m_pLock = NULL;
}
// request.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Work.h"
class Request
{
};
//Returns NULL if you want to complete
//the process, or a pointer to the memory
Request * GetRequest() throw()
{
return NULL;
}
//Process the request, but does not remove the memory
void ProcessRequest(Request * request) throw()
{
return;
}
const int NumberOfThreads = 2;
int _tmain(int argc, _TCHAR* argv[])
{
CWorkersMgr workersMgr;
//
//create work threads
workersMgr.CreateWorkers();
// get the request and put it into the queue in workers manager
Request *request = GetRequest();
while(request)
{
workersMgr.PushRequest(request);
request = GetRequest();
}
//
//wait until the Request has been processed
workersMgr.WaitUntilWorkComplete();
//
//destroy the work threads
workersMgr.DestroyWorkers();
return 0;
}