1.为什么使用线程池
      假使你设计了一个服务器程序,有监听线程不断的监听是否有从客户端发来的新登陆请求,如果收到新的请求,那么就新创建一个线程,做一系列针对该客户端的工作,而监听线程得以继续执行,以处理下一个登陆请求。新建的线程处理过登陆之后,很可能就没有其他任务了,因此该线程退出了。
      这里涉及到了线程的创建和销毁,如果在同一时刻收到了50000个登录请求,那就要循环创建50000个线程分别处理,可能当你创建到第500线程时,第一个线程已经退出了。此时频繁的创建和销毁线程所消耗的资源可能超出了线程本身执行正常任务所消耗的资源,这对于效率要求很高的应用是不合适的。
      此时可以考虑用线程池。

2.自己实现线程池
   
如果要自己实现线程池,简单的做法是首先要创建一个信标(semaphore)对象hSemaphore,并初始化可以容纳最多的作业数max,当前资源数为0。然后创建一定数量的工作线程(WorkThread),比如10个线程,这些线程都在循环中WaitForSingleObject(hSemaphore)。由于一开始信标的当前资源数是0,所以信标是unsigned,那么所有线程都处于等待状态。另创建一个任务队列(queue)以及一个工作项目添加函数(例如叫做AddWork(pfnWorkfun, pParam);),每当有新的任务要添加,都执行AddWork,在AddWork内部将pfnWorkfun和pParam配对的加入到任务队列的尾部(例如可以创建一个结构体等等),并调用ReleaseSemaphore使当前资源数增加1。当信标的当前资源数大于1的时候,会发出信号,所有等待的工作线程之一会获得执行。该工作线程pop出队列的第一项,然后在内部调用你的pfnWorkfun来完成具体的操作,最后对信标当前资源数量减1。直到信标当前资源数为0为止。
    上述实现只是简单介绍了流程,完全没有考虑线程的同步,以及动态增减待命工作线程等问题,具体实现时要注意。

3.使用系统提供的线程池
    系统提供了一个非常简单的使用线程池的方法,只需要调用一个函数即可,此函数就是QueueUserWorkItem
    调用该函数并传入例如(2)中所指定的pfnWorkfun以及pParam,系统便自动将此配对工作加入到线程池的工作队列中排队,当系统的线程池中有空闲的线程时就依次取出WorkItem并加以执行。
    这就是所谓的异步执行函数(Call Functions Asynchronously)。

4.当单一内核对象已通知时执行函数(Call Functions When Single Kernel Objects Become Signaled)
    和(3)类似,只不过不是手动添加pfnWorkfun和pParam了,而是注册一个内核对象hObject,并关联对应的pfnWorkfun和pParam。当该对象为signed时,自动添加该对工作到系统的线程池里,从而使得像工作可以执行。

5.当异步I/O完成请求时执行函数(Call Functions When Asynchronous I/O Requests Complete)
  

posted on 2008-03-05 11:38  悠然小调  阅读(3135)  评论(0编辑  收藏  举报