一个使用线程池的范例 翻译 BY LWKL
A programming model to use a thread pool by SherwoodHu
介绍许多场合我们需要利用多线程来提高我们系统的行为。每个线程序几乎相同,但我们必须管理这些线程。如果当系统繁忙了,那么我们将建立更多的线程序,不然我们杀掉一写来避免额外的负担。
我做了些涉及到多线程序管理的工作,最终我决定写一个来包装这些机制的类。此类能动态的分配线程和分配工作给这些线程。你只需要派生你自己的类,而并不需要知道内部的机制是如何操控制这多个线程和同步这些线程的。然而你必须保证你的工作类必须是线程安全的,原因是你的工作每时每刻都可能会被分派给不同的线程序。
另外,我还想描述下如何使用完成端口,我发现它极其简单和有用,特别是用作传在线程之间传输数据时。
使用要使用这个线程池类你必须从IWorker接口派生你的工作(WORK)类,从IJobDesc派生你的任务描述(JOB)类。工作的逻辑必须被包括在成员函数IWorker::ProcessJob(IJobDesc* pJob).,此后,你能像这样声明一个线程池:
CThreadPool pool;
pool.Start(6, 10);
//do some other jobs here
pool.Stop();
start函数拥有2个参数,第一个参数是线程池产生的最少线程个数。第2个参数指出最多工作线程的可能数。一方面如果线程序池非常繁忙,它就会自动产生更多的线程序,另一方面,当线程池空闲时,一些线程就会从池中被移走。好好设定这2个参数以便达到更好的表现。
如果想分配给工作给线程池,那么你只需简单的调用以下函数
pool.ProcessJob(pJob, pWorker);
你必须确保你继承的类是线程安全的,因为有可能一个工作实例可能同时工作在多线程里,你在任何情况下都无法得知工作是否工作在相同线程里。
提示如果你个工作过程非常耗时,那当你调用stop函数的时候,工作并不会立即停止。STOP函数将最多等待超过2分钟然后返回。此函数有一个可选参数,如果参数设定为TRUE,函数不管怎样都会停止这些工作线程。如果参数设定为FALSE,调这些工作线程将不会被野蛮的终止而回继续处在活动状态,在此情况下,你必须小心对待这些工作对象,当你调用STOP()后,如过你试图接近他们有可能你将会得到一个访问错误。
JOB对象必须有new操作符在堆上产生。结束后他将回自动被框架内部DELETE。
Sherwood Hu
评论有内存泄露
当我使用时候有一些内存泄露
ATL SERVER提供他自己的线程池类。
VS7及起以上版本,你可以使用内部的类 ATL::CThreadPool.工作原型以模板提供,应用3个共用方法和一个TYPEDEF定义工作项目。他非常通用,简单和速度快。当编写WINDOWS程序使用此类代替。
修正BUG
HI
首先非常感谢你分享你的代码
我想有一点BUG当WORKERPROC 接近(PROCESS) RemoveThread 信息(0xFFFFFFFE)的时候.,当线程接受到这个消息时候,整个的过程结束,线程序被终止。我们并不知道Processjob有没有完成。
所以我像这样修正了
修正
unsigned int CThreadPool::WorkerProc(void* p)
{
{
...
bool bBusy = false;
...
while(::GetQueuedCompletionStatus(IoPort, &pN1, &pN2, &pOverLapped, INFINITE ))
{
if(pOverLapped == (OVERLAPPED*)0xFFFFFFFE)
{
if(bBusy == false)
{
TRACE1("Server remove thread ID %d\n", threadId);
pServer->RemoveThread(threadId);
break;
}
else
TRACE1("Server remove thread ID %d BUSY\n", threadId);
}
else if(pOverLapped == (OVERLAPPED*)0xFFFFFFFF)
{
break;
}
else
{
...
bBusy = true;
pIWorker->ProcessJob(pIJob);
bBusy = false;
....
}
}
}
原地址
http://www.codeproject.com/threads/threadpool.asp
还有另外一个人做了些修正
详细请看地址
http://www.codeproject.com/threads/error_about_worker_thread.asp
另外一个问题,此处完成端口使用线程池的技术并不是先创建一个完成端口然后将他和一个句柄联系起来。而是使用了先创建一个完成端口,以后所有的工作都使用PostQueuedCompletionStatus 来传递参数和进行线程池内活动。大家看代码时候要注意下