1、线程池介绍
Windows提供了一个线程池机制来简化线程的创建、销毁、管理。使用系统提供的线程池机制相当方便而且很有效率,我们仅需要关注于我们的回调函数即可。我们可以自己来实现线程池机制,但是与我们的简单模拟来比,系统提供的线程池有着更多的优点:首先,线程池中线程的数目是动态调整的,其次,线程池利用IO完成端口的特性,它可以限制并发运行的线程数目,默认情况下,将会限制为与CPU数目相关的合理数目,这可以减少线程之间频繁切换。线程池还会挑选最近执行过的线程再次投入执行,从而避免了不必要的线程切换。系统提供的线程池背后的隐藏着巨大的策略。
在线程池编程中,我们从来不需要自己调用CreateThread.系统会自动为我们的进程创建线程,并在规定的条件下让线程池中的线程调用我们的回调函数.此外,这个线程在处理完成一个客户请求后,它不会立刻被销毁,而是回到线程池,准备好处理队列中的任何其他工作项,线程池会不断地重复使用其中的线程,而不会频繁地创建销毁线程,对应用程序来说,这样可以显著地提升性能,因为创建和销毁线程会消耗大量的时间.当然,如果线程池检测到创建的另一个线程将能更好地为应用程序服务,那么它会这样做.如果线程池检测到它的线程数量已经供过于求,那么它会销毁其中一些线程。
当一个进程初始化的时候,它并没有任何与线程池的开销.但是,一旦调用了线程池相关函数,系统就会为进程相应的内核资源,其中的一些资源在进程终止之前都将一直存在.正如我们可以看到,使用线程池的开销取决于用法:系统会以进程的名义来分配线程,其他内核以及内部数据结构.因此我们不应该盲目地使用这些线程池函数,而是必须谨慎地考虑,这些函数能做什么,以及它们不能做什么.
2、线程池应用范围
下面是我总结的一些线程池应用范围,可能是不全面的:
- 需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。 但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
- 对性能要求苛刻的应用,比如要求服务器迅速相应客户请求。
- 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,并出现"OutOfMemory"的错误。
3、新旧线程池技术
新的线程池函数必须在Vista操作系统或以上实现,且 C++ 编译器版本至少是 VS2008;旧的线程池函数则可以在2000/XP下实现:
Vista/2008/7(大多实现在用户态,效率更高):
线程池能够帮助我们做一下事情:
①:以异步的方式调用一个函数。
②:每隔一段时间调用一个函数。
③:当内核对象触发时调用一个函数。
④:当异步IO完成时调用一个函数。
①、 以异步的方式调用一个函数CreateThreadpoolWork():为线程池创建一个提交工作的工作对象。
SubmitThreadpoolWork():向线程池提交工作请求(可以多次提交)。
WaitForThreadpoolWorkCallbacks():取消已提交但未执行的工作项/等待工作项处理完成而将自己挂起。
CloseThreadpoolWork():关闭可以多次提交工作的工作对象。
eg:
#include<Windows.h>
#include<iostream>
#include<cstdlib>
using namespace std;
VOID CALLBACK WorkCallback(PTP_CALLBACK_INSTANCE Instance,PVOID Context,PTP_WORK Work)
{
cout<<"this is WorkCallback function!"<<endl;
}
void main()
{
PTP_WORK tpWork;
//创建工作对象
tpWork = CreateThreadpoolWork(WorkCallback,NULL,NULL);
//多次提交工作
SubmitThreadpoolWork(tpWork);
SubmitThreadpoolWork(tpWork);
SubmitThreadpoolWork(tpWork);
//等待工作结束
WaitForThreadpoolWorkCallbacks(tpWork,false);
//关闭工作对象
CloseThreadpoolWork(tpWork);
system("pause");
}
即内核对象触发时异步(使用线程池中的一个线程)执行一个函数,CreateThreadpoolWait()函数用来创建线程池等待对象,设置回调函数和传入的参数,SetThreadpoolWait()函数将一个内核对象绑定到这个线程池等待对象。
如果不调用StartThreadpoolIo函数则不会调用回调函数。当不需要读写设备文件后调用CloseThreadpoolIo()解除设备文件与线程池IO对象的关系。
/*
http://www.cnblogs.com/kzloser/archive/2013/03/11/2909221.html
http://blog.csdn.net/ithzhang/article/details/8373243
转载出处:http://blog.csdn.net/augusdi/article/details/5683907
http://www.ibm.com/developerworks/cn/java/l-threadPool/
http://blog.sina.com.cn/s/blog_4673b4ff01011clk.html
http://www.cnblogs.com/kzloser/archive/2013/03/11/2909221.html
http://blog.csdn.net/ithzhang/article/details/8373243