上一篇我把创建单个线程的源码给出来了,当然,线程池的也不能拉下~
很多时候,我们需要一组线程来解决问题。当然可以创建一些线程来完成工作,然后关闭掉。当又需要时,重复上述过程即可。然而,无论是客户端还是服务端,完全没必要如此,只需要实现创建一组线程,按需分配,不必创建--关闭--创建--关闭…
也许我们也能自己写成符合需求的线程池组件,但是,系统也提供了线程池组件。我认为就应该重复利用(出于学习的目的另当别论)。在这里,主要针对XP系统,提供一组C++ wrap过的线程池组件和模仿ATL线程池。当然,使用系统的线程池有一定的限制(设置线程堆栈大小等)。但还是能满足大部分的需求。
首先,来看看系统线程池(据《Windows核心编程》所说,在内部都是用完成端口来管理的)
Windows 线程池中的线程有两种类型,一种可以用来处理异步I/O, 另一种则不能。前者依赖于IO完成端口,IOCP是一种Windows内核对象,它可以将线程和I/O端口绑定在特定的系统资源上,对带有完成端口的I/O进行处理是一个复杂的过程。
- QueueUserWorkItemPool--Windows将创建一个线程池,其中的一个线程将执行 回调函数,函数执行完成后,该线程返回线程池,等待新的任务。当然了,你不能在该线程的回调函数中执行ExitThread等破坏行为。线程池中的线程数量是动态的,Windows内部的调度算法决定当前线程工作负载的最佳方式。如果要执行长时间的处理工作,需要设置WT_EXECUTELONGFUNCTION。如果该线程不执行异步IO,则设置WT_EXECUTIONDEFAULT即可,如果需要执行异步IO,则应该设置WT_EXECUTEIONIOTHREAD标志来告诉线程池
- BindIOCompletionCallbackPool--服务器应用程序发出某些异步IO请求,当这些请求完成时,需要让一个线程池准备好来处理已完成的IO请求。BindIoCompletionCallback在内部调用CreateIoCompletionPort,传递hDevice和内部完成端口的句柄。调用该函数可以保证至少有一个线程始终在非IO组件中,与设备相关的完成键是重叠完成例程的地址。
这样,当该设备的IO运行完成时,非IO组件就知道调用哪个函数,以便能够处理已完成IO请求 - RegisterWaitForSingleObjectPool--线程池在等待一个事件,当该事件被激活时,会唤醒一个线程来执行注册的回调函数。
其次,来看如何使用,简单展示下QueueUserWorkItemPool,其他的则在Example中给出
class A
{
enum { Count = 1000000 };
public:
void DoWork()
{
LONG lVal = 0;
for(DWORD i = 0; i != Count; ++i)
{
InterlockedExchangeAdd(&lVal, i);
}
}
void DoWork(int nNum)
{
LONG lVal = 0;
for(DWORD i = 0; i != nNum; ++i)
{
InterlockedExchangeAdd(&lVal, i);
}
}
};
A a;
QueueUserWorkItemPool::Call(&A::DoWork, &a);
QueueUserWorkItemPool::CallEx(&A::DoWork, &a, nCount);
很简单,是吧,只需要设置回调函数,CallEx比Call多提供一个额外参数,当然可以是任意类型.
然而,在对于BindIOCompletionCallbackPool的设计时,为了区分每个不同的回调函数,把自己弄成了模板类,需要提供一个额外的模板参数来进行区分--
BindIOCompletionCallbackPool<1>::Call和BindIOCompletionCallbackPool<2>::Call
如果你有更好的建议,希望你能提出,大家共同提高。
所有的源码和示例以提供:(需要更改后缀,把.gif改为.rar,用右键下载)
猛击这里 猛击这里