今天见论坛里有问怎么样实现线程池。碰巧原来写过一个类似的。现在来说说。(下面的全是个人理解,不见得是正确的。)
1。先来说说线程池。为什么要使用线程池?
因为创建线程和释放线程是要消耗系统资源的,如果要完成一个工作要不停的创建和释放线程必然会造成很大的系统资源的浪费,所以用线程池。在线程本次工作完成后,不释放线程,让线程等待。再有需要让线程去完成的工作时就把原来创建的线程取过来继续使用。这样节省了重复的创建释放线程的过程。
2。如何实现功能。
根据上面的理解我们来实现这些工作。
A.我们先要创建一个容器来装这些已经创建的线程。
B.然后我们需要用一套机制来让我们知道容器中的线程哪个是空闲的。哪个正在工作。
开始动手写吧.
//.h文件
#ifndef MyThreadPoolH
#define MyThreadPoolH
#include <Classes.hpp>
//定义通讯消息
#define TP_AddThread WM_USER + 1001 //向容器添加一个线程
#define TP_DeleteThread WM_USER + 1002 //删除容器中的一个线程
#define TP_GetFreeThread WM_USER + 1003 //获取一个空闲线程
#define TP_GetThreadCount WM_USER + 1004 //得到容器中的线程总数
class MyThreadPool : public TObject
{
private:
HANDLE FHandle;//线程池的句柄 用来接收通讯消。
TList *FThreadList; //用一个TList来做容器
bool FError; //是否出现错误
void __fastcall (TMessage &Message);//消息处理函数
long __fastcall FGetThreadCount(void);//得到容器中线程的总数
public:
__fastcall MyThreadPool();
__fastcall ~MyThreadPool();
__published:
//发布属性
__property HNDLE Handle={read=FHandle};
__property bool Error={read=FError};
//__property TList *ThreadList={read=FThreadList};//如果有必要把容器发布出来 !但会降低安全性!
__property long ThreadCount={read=GetFreeThread};
};
#endif
//.cpp
#include <vcl.h>
#pragma hdrstop
#include "MyThreadPool.h"
#pragma package(smart_init)
__fastcall MyThreadPool::MyThreadPool()
{
FError=false;
FHandle=AllocateHWnd(MyProc);//创建一个窗口句柄来处理消息
if(FHandle==NULL)
{
FError=true;
return;
}
FThreadList=new TList;//创建容器
if(FThreadList==NULL)
{
FError=true;
return;
}
}
__fastcall MyThreadPool::~MyThreadPool()
{
if(FHandle!=NULL)//释放句柄
{
DeallocateHWnd(FHandle);
}
if(FThreadList!=NULL)//释放容器
{//这里只把容器中的线程指针给删除了。
//中间的线程并没有释放。要释放需要自己添加代码
FThreadList->Clear();
delete FThreadList;
}
}
//处理消息
void __fastcall MyThreadPool::MyProc(TMessage &Message)
{
void *pThread;
int ret;
switch(Message.Msg)
{
case TP_AddThread://添加线程的时候消息的WParam参数为线程指针
pThread=(void *)Message.WParam;
ret=FThreadList->Add(pThread);
Message.Result=ret;//返回线程指针在容器中的index
return;
case TP_DeleteThread://删除线程时消息的WParam参数为线程指针
pThread=(void *)Message.WParam;
ret=FThreadList->IndexOf(pThread);
//如果线程指针不在容器中返回-1,成功删除返回1
if(ret==-1)
{
Message.Result=-1;
}
else
{
FThreadList->Delete(ret);
Message.Result=1;
}
return;
case TP_GetFreeThread://得到一个空闲的线程,如果有空闲消息返回值为线程指针。
//一但线程给取出线程的Working属性就倍设置成true;
for(int i=0;i<FThreadList->Count;i++)
{
pThreadFThreadList->Items[i];
if(((TMyThread *)pThread)->Working==false)
{
((TMyThread *)pThread)->Working=true;
Message.Result=(long)pThread;
return;
}
}
Message.Result=0;
return;
case TP_GetThreadCount://返回容器中的总数
Message.Result=FThreadList->Count;
return;
}
try
{
Dispatch(&Message);
if(Message.Msg==WM_QUERYENDSESSION)
{
Message.Result=1;
}
}
catch(...){};
}
3。我们还需要定制一个自己的线程类来配合上面的ThreadPool来使用
class TMyThread : public TThread
{
private:
bool FWorking;
HANDLE PoolHandle
protected:
void __fastcall Execute();
public:
__fastcall TMyThread(bool CreateSuspended,HANDLE hHandle/*线程池的句柄*/);
__published:
//发布属性
__property bool Working={read=FWorking,write=FWorking}; //线程是否空闲
};
__fastcall TMyThread::TMyThread(bool CreateSuspended,HANDLE hHandle)
: TThread(CreateSuspended)
{
PoolHandle=hHandle;
FWorking=false;
}
void __fastcall TMyThread::Execute()
{
while(!Terminated)
{
FWorking=true;
//工作代码
//。。。。
FWorking=false;
this->Suspend();
}
::SendMessage(PoolHandle,TP_DeleteThread,(long)this,0);//在线程池的容器中删除本线程
return;//线程结束
}
4。下面来演示一下如何使用
//1.创建线程池对象
MyThreadPool *pMyTP=new MyThreadPool;
if(!pMyTP || pMyTP->Error)
{
//创建出错。
//。。。处理代码
}
//2.创建N个TMyThread线程对象,并加入线程池
TMyThread *pThread;
for(int i=0;i<N;i++)
{
pThread=new TMyThread(true,pMyTP->Handle);
::SendMessage(pMyTP->Handle,TP_AddThread,(long)pThread,0);
}
//3.从线程池中去空闲线程
TMyThread *pThread;
pThread=(TMyThread *)::SendMessage(pMyTP->Handle,TP_GetFreeThread,0,0);
if(pThread)//如果有空闲线程
{
pThread->Resume();
}
这样就大致实现了线程池的功能。这种东西我已经用在了程序里了。效果还不错节省了不少资源。但是可能和书上说的线程池还是有很大差别的。
我们暂且叫它线程池A。反正已经达到我开始的时候设计它的目的,节省了资源。
就当是抛砖引玉吧。希望这些代码能给兄弟们一点启发,对兄弟门有用。