线程池

      目的:减少创建与撤销线程以及切换的额外开销,
     简单实现分析:首先创建一个信标对象hSemaphore(初始化:可以容纳最多的作业数max,当前资源数为0)。然后创建一定数量的工作线程(WorkThread),比如10个线程,这些线程都在循环中WaitForSingleObject(hSemaphore)。由于一开始信标的当前资源数是0,所以信标是unsigned,那么所有线程都处于等待状态。另创建一个任务队列(queue)以及一个工作项目添加函数(例如叫做AddWork(pfnWorkfun, pParam)),每当有新的任务要添加,都执行AddWork,在AddWork内部将pfnWorkfun和pParam配对的加入到任务队列的尾部(例如可以创建一个结构体等等),并调用ReleaseSemaphore使当前资源数增加1。当信标的当前资源数大于1的时候,会发出信号,所有等待的工作线程之一会获得执行。该工作线程pop出队列的第一项,然后在内部调用你的pfnWorkfun来完成具体的操作,最后对信标当前资源数量减1。直到信标当前资源数为0为止。(完全没有考虑线程的同步,以及动态增减待命工作线程等问题,具体实现时要注意)
     但是,系统已经提供了一个非常简单的使用线程池的方法,只需要调用一个函数即可(QueueUserWorkItem)。调用该函数并传入例如(2)中所指定的pfnWorkfun以及pParam,系统便自动将此配对工作加入到线程池的工作队列中排队,当系统的线程池中有空闲的线程时就依次取出WorkItem并加以执行。这就是所谓的异步调用函数(Call Functions Asynchronously)。
BOOL QueueUserWorkItem(
   PTHREAD_START_ROUTINE pfnCallback,
   PVOID pvContext,
   ULONG dwFlags);
函数原型:DWORD WINAPI WorkItemFunc(PVOID pvContext);
­
1.异步方法调用
  异步方法调用有以下两种方法:
  (1)线程函数原型(回调函数)
       VOID NTAPI SimpleCallback(
       PTP_CALLBACK_INSTANCE pInstance,
       PVOID pvContext );
      TrySubmitThreadpoolCallback 该函数将线程函数执行请求发到线程池,并将一个"工作项目"添加到线程池的队列中。注:我们不需要调用CreateThread函数,线程池中的线程会执行我们的回调函数                  
  (2)显示控制"工作项目"
       CreateThreadpoolWork     创建一个工作项目
       SubmitThreadpoolWork     将工作项目提交到线程池中,一个工作项目可以多次提交到线程池中。
       WaitForThreadpoolWorkCallbacks    等待线程函数执行完毕或取消执行线程函数。            
       CreateThreadpoolWork要求的线程函数原型:
         VOID CALLBACK WorkCallback(
         PTP_CALLBACK_INSTANCE Instance,
         PVOID Context,
         PTP_WORK Work);
        VOID WaitForThreadpoolWorkCallbacks(
         PTP_WORK pWork,
         BOOL bCancelPendingCallbacks );
­
2.时间间隔内调用函数
     (1)CreateThreadpoolTimer要求的线程函数原型
         VOID CALLBACK TimeoutCallback (
         PTP_CALLBACK_INSTANCE pInstance,   // See "Callback Termination Actions" section
         PVOID pvContext,
         PTP_TIMER pTimer );
      (2)步骤
           CreateThreadpoolTimer
           SetThreadpoolTimer
           WaitForThreadpoolTimerCallbacks
           CloseThreadpoolTimer    
                    
3.当内核对象处于Signal状态时调用函数
   当指定的内核对象变成Signal状态或等待超时,线程池会用户指定的线程函数。之后当内核对象再次变成Signal状态时,线程函数不会被调用,除非再次调用SetThreadpoolWait注册线程函数。
   (1)CreateThreadpoolWait要求的线程函数原型
      VOID CALLBACK WaitCallback (
        PTP_CALLBACK_INSTANCE pInstance, // See "Callback Termination Actions" section
        PVOID Context,
        PTP_WAIT Wait,
        TP_WAIT_RESULT WaitResult );
­
       CreateThreadpoolWait
       SetThreadpoolWait 不允许多次注册同样的Handle,但是我们可以用DuplicateHandle函数复制一个句柄 然后再注册。
       WaitForThreadpoolWaitCallbacks
       CloseThreadpoolWait
­
4.当异步I/O请求结束后调用函数
      
5.回调终结后的操作和私有线程
posted @ 2009-06-17 10:43  辛勤耕耘  阅读(419)  评论(0)    收藏  举报