window下C++线程池实现

工作当中频繁使用到多线程,网上参考了一份代码,并根据自己需要改进了一下,贴出来做个记录,以后如果有产生问题还会继续改进。

大致介绍下每个类的作用:

1. CThread 线程基类,线程创建及销毁

2. CWorkerThread 工作线程,任务设置获取,池对象设置获取,线程运行及终止

3. CThreadPool 任务运行,空闲线程/忙碌线程管理,销毁线程池

4. CJob 需要执行的任务类,业务逻辑可继承此类

5. CThreadCondition 线程同步,条件变量类,由event触发等待实现

6. CThreadMutex 线程互斥,由临界区实现

7. CThreadManage 暴露给上层的类,主要集中线程池的运行与销毁

以下是各个文件的实现代码,记录一下:

// Thread.h

#ifndef THREAD_H_
#define THREAD_H_
#include "windows.h"

typedef enum _ThreadState
{
	THREAD_INI = -1,
	THREAD_RUNNING = 0,
	THREAD_IDLE = 1,
	THREAD_EXIT = 2,
}ThreadState;

class CThread
{

private:
	
	unsigned int 			m_threadID;
	HANDLE					m_threadHandle;
	char*					m_threadName;
	ThreadState				m_threadState;
	BOOL					m_isExit;

protected:
	
	static unsigned __stdcall ThreadFunction(void*);

public:
	
	CThread();
	virtual ~CThread();

	virtual void Run(void) = 0;

	BOOL Terminate(void);
	BOOL Start(void);

	void SetThreadState(ThreadState state)  {m_threadState = state;}
	ThreadState GetThreadState(void)	{return m_threadState;}
	
	void SetThreadName(char* thrName);
	char* GetThreadName(void)	{return m_threadName;}
	
	BOOL GetExit()	{return m_isExit;}
	void SetExit(BOOL exit)	{m_isExit = exit;}

	HANDLE GetThreadHandle()	{return m_threadHandle;}
	void   SetThreadHandle(HANDLE hdl)	{m_threadHandle = hdl;}

	int GetThreadID(void)	{return m_threadID;}
};
#endif //Thread.h

// Thread.cpp

#include "stdio.h"
#include 
#include 
#include "Thread.h"

CThread::CThread():
m_isExit(FALSE),
m_threadHandle(0),
m_threadID(0),
m_threadName(NULL),
m_threadState(THREAD_INIT)
{

}

CThread::~CThread()
{
	if (NULL != m_threadName)
	{
		free(m_threadName);
		m_threadName = NULL;
	}
}

BOOL CThread::Terminate()
{
	if (m_isExit)
	{
		_endthreadex(0);
		if (m_threadHandle)
			CloseHandle(m_threadHandle);
		return TRUE;
	}
	return FALSE;
}

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

BOOL CThread::Start()
{
	unsigned int threadID = 0;
	HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, this, 0, &threadID);
	if (hThread == 0)
	{
		printf("create thread fail, errno=%d, doserrno=%d\n", errno, _doserrno);
		return FALSE;
	}
	this->m_threadID = threadID;
	this->m_threadHandle = hThread;
	//printf("new thread [%d]\n", threadID);
	return TRUE;
}

void CThread::SetThreadName(char* thrName)
{
	if (NULL != m_threadName)
	{
		free(m_threadName);
		m_threadName = NULL;
	}

	if (NULL != thrName)
	{
		int mallocSize = strlen(thrName) + 1;
		m_threadName = (char*)malloc(mallocSize);
		memset(m_threadName, 0, mallocSize);
		strncpy_s(m_threadName, mallocSize, thrName, strlen(thrName));
	}
}
 
  

// WorkThread.h

#ifndef WORKER_THREAD_H_
#define WORKER_THREAD_H_
#include "Thread.h"
#include "ThreadCondition.h"
#include "ThreadMutex.h"

class CJob;
class CThreadPool;

class CWorkerThread : public CThread
{

private:
	
	CThreadPool* 			m_threadPool;
	CJob*					m_job;
	void*					m_jobData;

public:

	CThreadCondition		m_jobCond;

public:

	CWorkerThread();
	virtual ~CWorkerThread();
	void	Run();
	void	Terminate();
	void	SetJob(CJob* job, void* jobData);
	CJob*	GetJob(void)	{return m_job;}
	void	SetThreadPool(CThreadPool* thrPool);
	CThreadPool*	GetThreadPool(void)	{return m_threadPool;}	

};
#endif	//WorkerThread.h

// WorkThread.cpp

#include "stdio.h"
#include "ThreadPool.h"
#include "WorkerThread.h"
#include "Job.h"

CWorkerThread::CWorkerThread()
{
	m_job = NULL;
	m_jobData = NULL;
	m_threadPool = NULL;
}

CWorkerThread::~CWorkerThread()
{
}

void CWorkerThread::Run()
{
	for (;;)
	{
		// 等待任务
		while (m_job == NULL && !GetExit())
		{
			//printf("thread [%d] wait for job\n", GetThreadID());
			m_jobCond.Wait();
		}

		// 任务跳出 或 线程退出
		if (NULL == m_job)
		{
			if (GetExit())
				break;
			else
			{
				//printf("job illege, skip this job...\n");
				continue;
			}
		}

		//接收新任务
		//printf("thread [%d] accept job [%d]\n", GetThreadID(), m_job->GetJobNo());
		m_job->Run(m_jobData);
		
		if (m_job)
		{
			delete m_job;
			m_job = NULL;
		}
		m_jobData = NULL;
		m_threadPool->MoveToIdleList(this);

		//清理多余的空闲线程
		if (m_threadPool->m_idleList.size() > m_threadPool->GetAvailHighNum())
		{
			int num = m_threadPool->m_idleList.size() - m_threadPool->GetInitNum();
			m_threadPool->DeleteIdleThread(num);
		}
	}

	printf("thread [%d] exit\n", GetThreadID());
}

void CWorkerThread::SetJob(CJob* job, void* jobData)
{
	if (!job) return;

	m_job = job;
	m_jobData = jobData;
	job->SetWorkThread(this);
	m_jobCond.Signal();
	//printf("job [%d] add to thread pool\n", m_job->GetJobNo());
}

void CWorkerThread::SetThreadPool(CThreadPool* pool)
{
	if (!pool) return;

	m_threadPool = pool;
}

void CWorkerThread::Terminate()
{
	//结束线程前,先结束任务
	SetExit(TRUE);
	if (m_job)
	{
		delete m_job; 
		m_job = NULL;
	}
	m_jobData = NULL;
	//printf("thread [%d] ready to exit\n", GetThreadID());
	m_jobCond.Signal();
	HANDLE hThread = GetThreadHandle();
	if (hThread)
	{
		WaitForSingleObject(GetThreadHandle(), INFINITE);
		CloseHandle(GetThreadHandle());
	}
}	

// ThreadPool.h

#ifndef THREAD_POOL_H_
#define THREAD_POOL_H_

#include 
#include "ThreadCondition.h"
#include "ThreadMutex.h"

using namespace std;  

class CWorkerThread;
class CJob;

class CThreadPool
{
	friend class CWorkerThread;

public:

	CThreadPool();
	CThreadPool(int initNum);
	virtual ~CThreadPool();

	void TerminateAll(void);
	void Run(CJob* job, void* jobData);

	void SetMaxNum(int maxNum)	{m_maxNum = maxNum;}
	unsigned int  GetMaxNum(void)	{return m_maxNum;}
	void SetAvailLowNum(int minNum)	{m_availLow = minNum;}
	unsigned int  GetAvailLowNum(void)	{return m_availLow;}
	void SetAvailHighNum(int highNum)	{m_availHigh = highNum;}
	unsigned int  GetAvailHighNum(void)	{return m_availHigh;}
	unsigned int GetActualAvailNum(void)	{return m_availNum;}
	unsigned int  GetAllNum(void)	{return m_threadList.size();}
	unsigned int	 GetBusyNum(void)	{return m_busyList.size();}
	void SetInitNum(int initNum)	{m_initNum = initNum;}
	unsigned int  GetInitNum(void) {return m_initNum;}

protected:

	//获取一个空闲线程
	CWorkerThread* GetIdleThread(void);
	//追加新的空闲线程
	void AppendToIdleList(CWorkerThread* jobThread);
	//空闲线程转忙碌线程
	void MoveToBusyList(CWorkerThread* idleThread);
	//忙碌线程转空闲线程
	void MoveToIdleList(CWorkerThread* busyThread);
	//删除空闲线程
	void DeleteIdleThread(int num);
	//销毁空闲线程
	void DestroyIdleThread(CWorkerThread* idleThread);
	//创建新的空闲线程
	void CreateIdleThread(int num);

public:

	//临界区
	CThreadMutex			m_busyMutex;
	CThreadMutex			m_idleMutex;
	CThreadMutex			m_jobMutex;
	CThreadMutex			m_varMutex;

	//事件触发等待
	CThreadCondition		m_busyCond;
	CThreadCondition		m_idleCond;
	CThreadCondition		m_idleJobCond;
	CThreadCondition		m_maxNumCond;

	//线程列表
	vector m_threadList;
	//忙碌线程列表
	vector m_busyList;
	//空闲线程列表
	vector m_idleList;

	//线程常量
	static const int THREAD_MAX_NUM			= 30;
	static const int THREAD_INIT_NUM		= 10;
	static const int THREAD_AVAIL_LOW		= 5;
	static const int THREAD_AVAIL_HIGH		= 15;

private:

  //线程池允许并发的最大线程数目
  unsigned int m_maxNum;
  //线程池允许存在的最小空闲线程数目
  unsigned int m_availLow;
  //线程池允许存在的最大空闲线程数目
  unsigned int m_availHigh;
  //当前线程池中的实际空闲线程数目(size of m_idleList)
  unsigned int m_availNum;
  //初始创建的线程数目
  unsigned int m_initNum;

  //销毁线程池
  BOOL	m_shutDown;
};
#endif	//ThreadPool.h

// ThreadPool.cpp

#include "stdio.h"
#include "assert.h"
#include "stdlib.h"
#include 
#include "ThreadPool.h"
#include "WorkerThread.h"
#include "Job.h"

CThreadPool::CThreadPool():m_shutDown(FALSE)
{
	m_maxNum = CThreadPool::THREAD_MAX_NUM;
	m_availLow = CThreadPool::THREAD_AVAIL_LOW;
	m_initNum = m_availNum = CThreadPool::THREAD_INIT_NUM;
	m_availHigh = CThreadPool::THREAD_AVAIL_HIGH;

	//初始化线程数目不超过最大线程数目
	assert(m_initNum > 0 && m_initNum <= m_maxNum);

	//保证初始化的线程数目在最小和最大的空闲线程数目之间则合理
	assert(m_initNum >= m_availLow && m_initNum <= m_availHigh);

	m_threadList.clear();
	m_busyList.clear();
	m_idleList.clear();
	for (unsigned int i = 0; i < m_initNum; ++i)
	{
		CWorkerThread* thr = new CWorkerThread();
		assert(thr);
		thr->SetThreadPool(this);
		AppendToIdleList(thr);
		thr->Start();
	}
}

CThreadPool::CThreadPool(int initNum):m_shutDown(FALSE)
{
	m_maxNum = CThreadPool::THREAD_MAX_NUM;
	m_availLow = CThreadPool::THREAD_AVAIL_LOW;
	m_initNum = m_availNum = initNum;
	m_availHigh = CThreadPool::THREAD_AVAIL_HIGH;
	
	//初始化线程数目不超过最大线程数目
	assert(initNum > 0 && (unsigned int)initNum <= m_maxNum);

	//保证初始化的线程数目在最小和最大的空闲线程数目之间则合理
	assert((unsigned int)initNum >= m_availLow && (unsigned int)initNum <= m_availHigh);

	m_threadList.clear();
	m_busyList.clear();
	m_idleList.clear();
	for (unsigned int i = 0; i < (unsigned int)initNum; ++i)
	{
		CWorkerThread* thr = new CWorkerThread();
		assert(thr);
		thr->SetThreadPool(this);
		AppendToIdleList(thr);
		thr->Start();
	}
}

CThreadPool::~CThreadPool()
{
	m_threadList.clear();
	m_busyList.clear();
	m_idleList.clear();
}

void CThreadPool::TerminateAll()
{
	m_shutDown = TRUE;
	for (unsigned int i = 0; i < m_threadList.size(); ++i)
	{
		CWorkerThread* thr = m_threadList[i];
		if (!thr) continue;
		thr->Terminate();
		delete thr; thr = NULL;
	}
	return;
}

CWorkerThread* CThreadPool::GetIdleThread(void)
{
	if (m_shutDown) return NULL;

	while (m_idleList.size() == 0)
	{
		printf("no idle thread, wait pls...\n");
		m_idleCond.Wait();
	}

	m_idleMutex.Lock();
	if (m_idleList.size() > 0)
	{
		CWorkerThread* thr = (CWorkerThread*)m_idleList.front();
		if (!thr)
		{
			m_idleMutex.Unlock();
			return NULL;
		}
		//printf("get idle thread [%d]\n", thr->GetThreadID());
		m_idleMutex.Unlock();
		if (thr->GetThreadState() == THREAD_IDLE)
			return thr;
	}
	m_idleMutex.Unlock();

	return NULL;
}

void CThreadPool::AppendToIdleList(CWorkerThread* jobThread)
{
	if (m_shutDown) return;

	if (!jobThread) return;

	m_idleMutex.Lock();
	jobThread->SetThreadState(THREAD_IDLE);
	m_idleList.push_back(jobThread);
	m_threadList.push_back(jobThread);
	m_idleMutex.Unlock();	
}

void CThreadPool::MoveToBusyList(CWorkerThread* idleThread)
{
	if (m_shutDown) return;

	if (!idleThread) return;

	m_busyMutex.Lock();
	idleThread->SetThreadState(THREAD_BUSY);
	m_busyList.push_back(idleThread);
	m_availNum --;
	m_busyMutex.Unlock();

	m_idleMutex.Lock();
	vector::iterator iter;
	iter = find(m_idleList.begin(), m_idleList.end(), idleThread);
	if (iter != m_idleList.end())
		m_idleList.erase(iter);
	m_idleMutex.Unlock();
}

void CThreadPool::MoveToIdleList(CWorkerThread* busyThread)
{
	if (m_shutDown)	return;

	if (!busyThread) return;

	m_idleMutex.Lock();
	busyThread->SetThreadState(THREAD_IDLE);
	m_idleList.push_back(busyThread);
	m_availNum ++;
	m_idleMutex.Unlock();

	m_busyMutex.Lock();
	vector::iterator iter;
	iter = find(m_busyList.begin(), m_busyList.end(), busyThread);
	if (iter != m_busyList.end())
		m_busyList.erase(iter);
	m_busyMutex.Unlock();

	m_idleCond.Signal();
	m_maxNumCond.Signal();
}

void CThreadPool::CreateIdleThread(int num)
{
	if (m_shutDown)	return;

	if (num <= 0) return;

	printf("add new %d threads\n", num);
	for (int i = 0; i < num; ++i)
	{
		CWorkerThread* thr = new CWorkerThread();
		if (!thr) continue;
		thr->SetThreadPool(this);
		AppendToIdleList(thr);
		m_varMutex.Lock();
		m_availNum ++;
		m_varMutex.Unlock();
		thr->Start();
	}
}

void CThreadPool::DeleteIdleThread(int num)
{
	if (m_shutDown)	return;

	if (num <= 0) return;

	m_idleMutex.Lock();

	//如果空闲线程数目小于允许最大空闲线程数目,则不再删除
	if (m_idleList.size() < m_availHigh) 
	{
		printf("idle thread list size=%d\n", m_idleList.size());
		m_idleMutex.Unlock();
		return;
	}

	///TIPS:如果空闲列表头节点线程无效,则本次删除操作失效
	printf("delete %d threads\n", num);
	for (int i = 0; i < num; ++i)
	{
		CWorkerThread* thr = NULL;
		if (m_idleList.size() > 0)
			thr = (CWorkerThread*)m_idleList.front();

		if (!thr) continue;
		if (THREAD_IDLE != thr->GetThreadState()) continue;
		vector::iterator  iter;
 		iter = find(m_idleList.begin(), m_idleList.end(), thr);
  		if (iter != m_idleList.end())
		{
			//printf("delete thread [%d]\n", (*iter)->GetThreadID());
			DestroyIdleThread(*iter);
    		m_idleList.erase(iter);
		}

  		m_availNum --;
	}
	printf("after delete, idle threads num:%d, idle list size=%d\n", m_availNum, m_idleList.size());
	m_idleMutex.Unlock();
}

void CThreadPool::DestroyIdleThread(CWorkerThread* idleThread)
{
	if (m_shutDown)	return;

	if (!idleThread) return;

	if (THREAD_IDLE != idleThread->GetThreadState()) return;

	vector::iterator  iter;
	iter = find(m_threadList.begin(), m_threadList.end(), idleThread);
	if (iter != m_threadList.end())
	{
		CWorkerThread *delThread = *iter;
		if (!delThread) return;
		delThread->Terminate();
		delete delThread; delThread = NULL;
		m_threadList.erase(iter);
	}
}

void CThreadPool::Run(CJob* job, void* JobData)
{
	if (m_shutDown)	return;

	assert(job != NULL);

	//线程池已经达到最大并发数目,则等待
	if (GetBusyNum() >= m_maxNum)
	{
		printf("busy threads reach max permit num:%d\n", m_maxNum);
		m_maxNumCond.Wait();
	}

	//补充空闲线程(保持空闲线程数目为m_initNum)
	if (m_idleList.size() < m_availLow)
	{
		if (GetAllNum() + m_initNum - m_idleList.size() < m_maxNum)
			CreateIdleThread(m_initNum - m_idleList.size());
		else
			CreateIdleThread(m_maxNum - GetAllNum());
	}

	CWorkerThread* idleThr = GetIdleThread();
	if (idleThr != NULL)
	{
		MoveToBusyList(idleThr);
		idleThr->SetThreadPool(this);
		job->SetWorkThread(idleThr);
		idleThr->SetJob(job, JobData);
		//printf("job [%d] is bind to thread [%d]\n", job->GetJobNo(), idleThr->GetThreadID());
	}
}




// Job.h

#ifndef JOB_H_
#define JOB_H_

class CThread;
class CJob
{

private:
	
	int		m_jobNo;
	char*		m_jobName;
	CThread*	m_pWorkThread;

public:
	
	CJob();
	virtual ~CJob();

	int	GetJobNo() const	{return m_jobNo;}
	void SetJobNo(int JobNo)	{m_jobNo = JobNo;}
	char*	GetJobName() const	{return m_jobName;}
	void SetJobName(char* JobName);
	CThread* GetWorkThread()	{return m_pWorkThread;}
	void	SetWorkThread(CThread *pWorkThread)	{m_pWorkThread = pWorkThread;}
	virtual void Run(void* ptr) = 0;
};
#endif	//Job.h

// Job.cpp

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "Job.h"

CJob::CJob()
:m_pWorkThread(NULL),
m_jobNo(0),
m_jobName(NULL)
{
}

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

	m_pWorkThread = NULL;
}

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

	if (NULL != jobName)
	{
		int mallocSize = strlen(jobName) + 1;
		m_jobName = (char*)malloc(mallocSize);
		memset(m_jobName, 0, mallocSize);
		strncpy_s(m_jobName, mallocSize, jobName, strlen(jobName));
	}
}

// ThreadCondition.h

#ifndef THREAD_CONDITION_H_
#define THREAD_CONDITION_H_
#include "windows.h"

class CThreadCondition
{

private:

	HANDLE m_hCond;

public:

	CThreadCondition();
	~CThreadCondition();

	void Wait();
	void Signal();
};

#endif	//ThreadCondition.h

// ThreadCondition.cpp

#include "windows.h"
#include "ThreadCondition.h"

CThreadCondition::CThreadCondition()
{
	m_hCond = ::CreateEvent(NULL, TRUE, FALSE, NULL);
}

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

void CThreadCondition::Wait()
{
	WaitForSingleObject(m_hCond, INFINITE);  
	ResetEvent(m_hCond);
}

void CThreadCondition::Signal()
{
	SetEvent(m_hCond);
}

// ThreadMutex.h

#ifndef THREAD_MUTEX_H_
#define THREAD_MUTEX_H_

class CThreadMutex
{

private:
	CRITICAL_SECTION m_cs;

public:
	
	CThreadMutex();
	~CThreadMutex();

	BOOL Lock();
	BOOL Unlock();
	BOOL TryLock();
};

#endif	//ThreadMutex.h

// ThreadMutex.cpp

#include "windows.h"
#include "ThreadMutex.h"

CThreadMutex::CThreadMutex()
{
	::InitializeCriticalSection(&m_cs);
}

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

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

BOOL CThreadMutex::Unlock()
{
	::LeaveCriticalSection(&m_cs);
	return TRUE;
}

BOOL CThreadMutex::TryLock()
{
	BOOL ret = TryEnterCriticalSection(&m_cs);
	return ret;
}

// ThreadManage.h

#ifndef THREAD_MANAGE_H_
#define THREAD_MANAGE_H_

class CJob;
class CThreadPool;

class CThreadManage
{

private:
	
	//线程池指针
	CThreadPool* 		m_pool;
	//初始创建线程数目
	int			m_numOfThread;

public:
	
	CThreadManage();
	CThreadManage(int num);
	virtual ~CThreadManage();

	void Run(CJob* job, void* jobData);
	void TerminateAll(void);
};

#endif //ThreadManage.h

// ThreadManage.cpp

#include "ThreadManage.h"
#include "ThreadPool.h"
#include "Job.h"

CThreadManage::CThreadManage()
{
	m_numOfThread = 10;
	m_pool = new CThreadPool(m_numOfThread);
}

CThreadManage::CThreadManage(int num)
{
	m_numOfThread = num;
	m_pool = new CThreadPool(m_numOfThread);
}

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

void CThreadManage::Run(CJob* job, void* jobData)
{
	m_pool->Run(job, jobData);
}

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


使用上述线程池的简单示例:

#include "stdio.h"
#include "windows.h"
#include "Job.h"
#include "ThreadManage.h"
#include 


class CXJob:public CJob
{

public:

	CXJob()		{}
	~CXJob()	{}
	void Run(void* jobData)
	{		
		std::cout << "##The Job comes from CXJob" << std::endl;
		Sleep(2);
	}

};

class CYJob:public CJob
{

public:

  CYJob()	{}
  ~CYJob()  {}
  void Run(void* jobData)
  {
	  std::cout << "##The Job comes from CYJob" << std::endl;
	  Sleep(2);
  }

};
void main()
{
	CThreadManage* manage = new CThreadManage(10);
	for (int i = 1; i <= 1000; ++i)
	{
		CXJob* job = new CXJob();
		job->SetJobNo(i);
		job->SetJobName("JobX");
		int *data = &i;
		manage->Run(job, data);
	}

	Sleep(200);

	CYJob* job = new CYJob();
	int j = 1;
	job->SetJobNo(j);
	job->SetJobName("JobY");
	manage->Run(job, NULL);

	printf("--------terminate all thread--------\n");
	manage->TerminateAll();
	delete manage; manage = NULL;
}

 
  


你可能感兴趣的:(C++)