工作当中频繁使用到多线程,网上参考了一份代码,并根据自己需要改进了一下,贴出来做个记录,以后如果有产生问题还会继续改进。大致介绍下每个类的作用:
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;
}