最近脑袋有点犯贰。最近的工作总是涉及多线程,但网上的代码通用性不强。虽然windows已经内置了线程池,但是只能是VS2003以上的才能用,于是心一横就自己动手写了个线程池。
该线程池可以在CONSOLE程序和GUI程序中都可用,如果想添加或者修改什么功能,可在源代码基础上进行。
该线程池的包含了线程池和监视线程两个部分。线程池负责生成线程并响应外部的请求,监视线程负责监听外部线程请求,并从线程池获取可用的线程并执行。外部请求的工作函数必须符合 unsigned workFunc(void* pvParam) 形式,至于函数名可随意指定。工作函数可以是相同的函数也可以是不同的功能函数,这里就实现了功能定制。
使用线程池之前,首先初始化线程池并指定线程池的容量大小,指定的容量大小不能大于线程池的最大容量。线程池默认容量大小为10,为了达到最好的性能和效率,建议使用者将线程池的容量设定为计算机CPU个数的2倍(这是一条经验规则)。
初始化完成后可以向线程池添加工作函数,请遵循工作函数的原型规则。此时监视线程会向线程池请求一个可用的线程,如果线程请求已满,监视线程会循环检查可用的线程,如果得到一个可用的线程,将执行该工作函数。
该线程池已经过本人的详细测试,如果还出现了问题请回复或者自行解决。
一个使用用例:
该线程池可以在CONSOLE程序和GUI程序中都可用,如果想添加或者修改什么功能,可在源代码基础上进行。
该线程池的包含了线程池和监视线程两个部分。线程池负责生成线程并响应外部的请求,监视线程负责监听外部线程请求,并从线程池获取可用的线程并执行。外部请求的工作函数必须符合 unsigned workFunc(void* pvParam) 形式,至于函数名可随意指定。工作函数可以是相同的函数也可以是不同的功能函数,这里就实现了功能定制。
使用线程池之前,首先初始化线程池并指定线程池的容量大小,指定的容量大小不能大于线程池的最大容量。线程池默认容量大小为10,为了达到最好的性能和效率,建议使用者将线程池的容量设定为计算机CPU个数的2倍(这是一条经验规则)。
初始化完成后可以向线程池添加工作函数,请遵循工作函数的原型规则。此时监视线程会向线程池请求一个可用的线程,如果线程请求已满,监视线程会循环检查可用的线程,如果得到一个可用的线程,将执行该工作函数。
该线程池已经过本人的详细测试,如果还出现了问题请回复或者自行解决。
下面贴出线程池源代码和一个使用用例。
线程池头文件:
// CThreadPool.h: interface for the CThreadPool class.
//
//
#if !defined(AFX_CTHREADPOOL_H__8015A6DC_2CCD_4436_AD0F_4F5178B69DA4__INCLUDED_)
#define AFX_CTHREADPOOL_H__8015A6DC_2CCD_4436_AD0F_4F5178B69DA4__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <afx.h>
#include <process.h>
typedef unsigned (/*__stdcall*/ *PWORKPROC)(void* pvParam);
typedef struct _Thread
{
PWORKPROC pWorkFunc;
void* pvParam;
}Thread;
typedef struct _threadInfo
{
BOOL bValid;
UINT uiParamLen;
UINT uiThreadId;
UINT uiThreadIndex;
Thread thread;
HANDLE hThread;
HANDLE hEvent;
}ThreadInfo;
#define MAX_CAPACITY 20 //
class CThreadPool
{
public:
CThreadPool();
CThreadPool(UINT uiMaxCapacity);
void IncreaseThreadCount();
int GetRequestCount();
void DescendThreadCount();
void ResetThreadInfo(UINT uiIndex);
UINT GetValidThread(void);
UINT GetMaxCapacity(void);
UINT GetCurrentCount();
void AddWorkItem(PWORKPROC workFunc, void* pvParam);
UINT GetCapacity(void);
int InitThreadPool(UINT uiCapacity=8);
virtual void DisplayAllThreadInfo(void);
Thread* GetThreads();
ThreadInfo* GetThreadInfo();
static CThreadPool* GetCurrentPool(void);
virtual ~CThreadPool();
private:
static CThreadPool* m_poCurrentPool;
ThreadInfo* m_pThreadInfo;
int m_iReqCount;
UINT m_uiCurrentCount;
UINT m_uiMaxCapacity;
UINT m_uiPoolCapacity;
Thread* m_pThreads;
};
#endif // !defined(AFX_CTHREADPOOL_H__8015A6DC_2CCD_4436_AD0F_4F5178B69DA4__INCLUDED_)
// CThreadPool.cpp: implementation of the CThreadPool class.
//
//
#include "CThreadPool.h"
CThreadPool* CThreadPool::m_poCurrentPool=NULL;
unsigned __stdcall ThreadProc(void* pvParam);
unsigned __stdcall ListenThread(void* pvParam);
HANDLE hListenThread=NULL;
//
// Construction/Destruction
//
CThreadPool::CThreadPool()
{
m_uiMaxCapacity=MAX_CAPACITY;
m_poCurrentPool=this;
}
CThreadPool::CThreadPool(UINT uiMaxCapacity)
{
m_uiMaxCapacity=uiMaxCapacity;
m_poCurrentPool=this;
}
CThreadPool::~CThreadPool()
{
if (m_pThreadInfo!=NULL)
{
delete (m_pThreadInfo);
m_pThreadInfo=NULL;
}
if (m_pThreads!=NULL)
{
delete (m_pThreads);
m_pThreads=NULL;
}
for (UINT loop=0;loop<m_uiPoolCapacity;loop++)
{
CloseHandle(m_pThreadInfo[loop].hThread);
CloseHandle(m_pThreadInfo[loop].hEvent);
}
CloseHandle(hListenThread);
}
int CThreadPool::InitThreadPool(UINT uiCapacity)
{
HANDLE hThread=NULL;
HANDLE hEvent=NULL;
UINT uiThreadId=0;
UINT loop=0;
m_pThreadInfo=NULL;
m_uiCurrentCount=0;
m_iReqCount=0;
if (uiCapacity>m_uiMaxCapacity)
{
return -1;
}
m_uiPoolCapacity=uiCapacity;
m_pThreadInfo=new ThreadInfo[uiCapacity];
m_pThreads=new Thread[MAX_CAPACITY];
for (;loop<MAX_CAPACITY;loop++)
{
m_pThreads[loop].pvParam=NULL;
m_pThreads[loop].pWorkFunc=NULL;
}
for (loop=0;loop<m_uiPoolCapacity;loop++)
{
m_pThreadInfo[loop].bValid=TRUE;
m_pThreadInfo[loop].thread.pWorkFunc=NULL;
m_pThreadInfo[loop].thread.pvParam=NULL;
m_pThreadInfo[loop].uiParamLen=0;//
m_pThreadInfo[loop].uiThreadIndex=loop;
m_pThreadInfo[loop].hThread=NULL;
m_pThreadInfo[loop].hEvent=NULL;
hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
if (hEvent==NULL)
{
return -2;
}
m_pThreadInfo[loop].hEvent=hEvent;
hThread=(HANDLE)_beginthreadex(NULL,0,ThreadProc,(void*)(&m_pThreadInfo[loop].uiThreadIndex),0,&uiThreadId);//
if (hThread==NULL)
{
return -3;
}
m_pThreadInfo[loop].uiThreadId=uiThreadId;
m_pThreadInfo[loop].hThread=hThread;
}
hListenThread=(HANDLE)_beginthreadex(NULL,0,ListenThread,NULL,0,NULL);//
if (hListenThread==NULL)
{
return -4;
}
return 0;
}
unsigned __stdcall ThreadProc(void* pvParam)
{
CThreadPool* threadPool=NULL;
ThreadInfo* threadInfo=NULL;
PWORKPROC workProc=NULL;
void* workParam=NULL;
UINT uiIndex=0;
uiIndex=*(int*)pvParam;
threadPool=CThreadPool::GetCurrentPool();
threadInfo=threadPool->GetThreadInfo();
while(TRUE)
{
if (WaitForSingleObject(threadInfo[uiIndex].hEvent,INFINITE)!=WAIT_OBJECT_0)
{
continue ;
}
workProc=NULL;
workParam=NULL;
//printf("Execute thread:index=%d\thandle=%p\n", uiIndex,threadInfo[uiIndex].hThread);//
workProc=threadInfo[uiIndex].thread.pWorkFunc;
workParam=threadInfo[uiIndex].thread.pvParam;
if (workProc!=NULL)
{
workProc(workParam);
}
threadPool->ResetThreadInfo(uiIndex);
threadPool->DescendThreadCount();
}
return 0;
}
void CThreadPool::AddWorkItem(PWORKPROC workFunc, void *pvParam)
{
m_pThreads[m_iReqCount%MAX_CAPACITY].pWorkFunc=workFunc;
m_pThreads[m_iReqCount%MAX_CAPACITY].pvParam=pvParam;
m_iReqCount++;
}
unsigned __stdcall ListenThread(void* pvParam)
{
CThreadPool* threadPool=NULL;
ThreadInfo* threadInfo=NULL;
Thread* threads=NULL;
PWORKPROC workProc=NULL;
void* workParam=NULL;
int iReqCount=0;
int uiIndex=0;
threadPool=CThreadPool::GetCurrentPool();
threadInfo=threadPool->GetThreadInfo();
threads=threadPool->GetThreads();
while(TRUE)
{
while(iReqCount!=threadPool->GetRequestCount())
{
workProc=NULL;
workParam=NULL;
uiIndex=threadPool->GetValidThread();
//线程池请求已满,此处循环等待可用的线程
if (uiIndex<0)
{
continue ;
}
//printf("Request thread index:%d\n", uiIndex);
threadPool->IncreaseThreadCount();
workProc=threads[iReqCount%MAX_CAPACITY].pWorkFunc;
workParam=threads[iReqCount%MAX_CAPACITY].pvParam;
threadInfo[uiIndex].bValid=FALSE;
threadInfo[uiIndex].thread.pvParam=workParam;
threadInfo[uiIndex].thread.pWorkFunc=workProc;
threadInfo[uiIndex].uiParamLen=0;//
SetEvent(threadInfo[uiIndex].hEvent);
iReqCount++;
}
}
return 0;
}
void CThreadPool::DisplayAllThreadInfo()
{
//printf("Display all information of thread.\n");
for (UINT loop=0;loop<GetCapacity();loop++)
{
//printf("\tIndex:%d\tHandle:%p\tThreadId:%d\n", m_pThreadInfo[loop].uiThreadIndex,m_pThreadInfo[loop].hThread,m_pThreadInfo[loop].uiThreadId);
}
//printf("\n");
}
void CThreadPool::ResetThreadInfo(UINT uiIndex)
{
m_pThreadInfo[uiIndex].bValid=TRUE;
m_pThreadInfo[uiIndex].uiParamLen=0;//
m_pThreadInfo[uiIndex].thread.pvParam=NULL;
m_pThreadInfo[uiIndex].thread.pWorkFunc=NULL;
}
UINT CThreadPool::GetValidThread()
{
for (UINT loop=0;loop<GetCapacity();loop++)
{
if (m_pThreadInfo[loop].bValid==TRUE)
{
return m_pThreadInfo[loop].uiThreadIndex;
}
}
return -1;
}
UINT CThreadPool::GetCapacity()
{
return m_uiPoolCapacity;
}
CThreadPool* CThreadPool::GetCurrentPool()
{
return m_poCurrentPool;
}
UINT CThreadPool::GetCurrentCount()
{
return m_uiCurrentCount;
}
UINT CThreadPool::GetMaxCapacity()
{
return m_uiMaxCapacity;
}
ThreadInfo* CThreadPool::GetThreadInfo()
{
return m_pThreadInfo;
}
void CThreadPool::DescendThreadCount()
{
--m_uiCurrentCount;
}
int CThreadPool::GetRequestCount()
{
return m_iReqCount;
}
void CThreadPool::IncreaseThreadCount()
{
m_uiCurrentCount++;
}
Thread* CThreadPool::GetThreads()
{
return m_pThreads;
}
一个使用用例:
#include "CThreadPool.h"
unsigned Test(void* param)
{
printf("TEST%s for multiple threads.\n", (char*)param);
return 0;
}
int main(int argc, char* argv[])
{
CThreadPool pool;
int iRet=0;
iRet=pool.InitThreadPool(4);
if (iRet<0)
{
printf("Initial thread pool;iRet=%d\n",iRet);
return EXIT_FAILURE;
}
pool.DisplayAllThreadInfo();
pool.AddWorkItem(Test,"0");
//Sleep(1000);
pool.AddWorkItem(Test,"1");
//Sleep(1000);
pool.AddWorkItem(Test,"2");
//Sleep(1000);
pool.AddWorkItem(Test,"3");
//Sleep(1000);
pool.AddWorkItem(Test,"4");
WaitMessage(); //此处不可少
return EXIT_SUCCESS;
}