现在的位置: 首页 > 综合 > 正文

《Windows核心编程》读书笔记——Windows线程池

2013年10月05日 ⁄ 综合 ⁄ 共 7895字 ⁄ 字号 评论关闭

 

         JeffreyRichter的《windows核心编程》里提到的windows线程池功能,他把这些功能分为四类:

         以异步的方式来调用一个函数;

         每隔一段时间调用一个函数;

         当内核对象触发的时候调用一个函数;

         当异步I/O请求完成的时候调用一个函数;

 

         以下按这四种类型功能,结合其调用函数接口和程序例子,来详细讨论其用法。

 

以异步的方式来调用一个函数

         直接以异步方式调用函数也有两种API方式。

隐式控制工作项

         这种方式需要两个函数配合使用:需要在线程池中获取线程来调用的函数必须以SimpleCallback函数指针的方式声明,再在主线程中使用用TrySubmitThreadpoolCallback函数设置此回调函数。TrySubmitThreadpoolCallback函数会调用PostQueuedCompletionStatus来将这个SimpleCallback函数的工作项加入到线程池队列中,如果成功的话,返回TRUE,失败返回FALSESimpleCallback声明的函数是否立即调用要看CPU的调度。

 

VOIDCALLBACK SimpleCallback(

  _Inout_     PTP_CALLBACK_INSTANCE Instance,

  _Inout_opt_ PVOID Context

);

 

BOOLWINAPI TrySubmitThreadpoolCallback(

  _In_        PTP_SIMPLE_CALLBACK pfns,

  _Inout_opt_ PVOID pv,

  _In_opt_    PTP_CALLBACK_ENVIRON pcbe

);

         我们不需要自己调用CreateThread来产生线程,系统会为我们的进程创建一个默认的线程池,并让线程池中的一个线程来调用我们的回调函数。这个线程池是windows精心设计的,其原理在《windows核心编程》里面讲述了一些,我尽量找多一些资料佐证这个说法。

         下面一个简单的例子展示了隐式控制工作项的这两个函数的使用。

#include "stdafx.h"

#include <windows.h>

VOID
CALLBACK
MySimpleCallBack(PTP_CALLBACK_INSTANCE
Instance,PVOID
Context)

{

     _tprintf(_T("This iscalling Test_1_SimpleCallBack!"));

     return;

}

int main(void)

{

     BOOL
ret
= TrySubmitThreadpoolCallback(MySimpleCallBack,NULL,NULL);

     Sleep(10000);

}

     以上的例子有一个明显的问题,没有对MySimpleCallBack调用的线程做同步的等待。如果主线程main已经退出,但MySimpleCallBack函数所在线程还在执行,可能造成的后果是未定义的。后面会讨论怎么解决这个问题,这里不详细展开。还应该注意,TrySubmitThreadpoolCallback不是一定可以调用成功的,在某些情况下,函数内部做线程调度的工作会遇到很多问题。

 

显式的控制工作项

         有时我们可能需要先创建多个工作项,然后逐个加入到线程池中执行,这个时候(也是通常的时候)需要使用显式控制工作项的函数。

         使用CreateThreadpoolWork函数创建工作项,线程池会调用这个函数给出的回调函数参数WorkCallback函数指针,使用SubmitThreadpoolWork提交工作项,使用WaitForThreadpoolWorkCallbacks等待工作项完成的事件,最后,使用CloseThreadpoolWork关闭工作项。下面的这些函数的原型。

 

创建工作项,传进工作需要的回调函数:

PTP_WORKWINAPI CreateThreadpoolWork(

  _In_        PTP_WORK_CALLBACK pfnwk,

  _Inout_opt_ PVOID pv,

  _In_opt_    PTP_CALLBACK_ENVIRON pcbe

);

 

供线程调用的回调函数原型:

VOIDCALLBACK WorkCallback(

  _Inout_     PTP_CALLBACK_INSTANCE Instance,

  _Inout_opt_ PVOID Context,

  _Inout_     PTP_WORK Work

);

 

提交工作项,让线程池创建一个新线程去调用回调函数:

VOIDWINAPI SubmitThreadpoolWork(

  _Inout_ PTP_WORK pwk

);

 

等待工作项的线程完成回调函数调用:

VOIDWINAPI WaitForThreadpoolWorkCallbacks(

  _Inout_ PTP_WORK pwk,

  _In_    BOOL fCancelPendingCallbacks

);

 

关闭工作项:

VOIDWINAPI CloseThreadpoolWork(

  _Inout_ PTP_WORK pwk

);

 

下面上例子说明一个极简单的调用情景:

VOID CALLBACK MyWorkCallback(PTP_CALLBACK_INSTANCE
Instance,PVOID
Parameter,PTP_WORK
Work)

{

     _tprintf(_T("This iscalling Test_1_WorkCallback!"));

     return;

}

int main(void)

{

     PTP_WORKpwWork =
CreateThreadpoolWork(MyWorkCallback,NULL,NULL);

     SubmitThreadpoolWork(pwWork);

     WaitForThreadpoolWorkCallbacks(pwWork,FALSE);

     CloseThreadpoolWork(pwWork);

     return  0;

}

 

每隔一段时间调用一个函数

 

CreateThreadpoolTimer

 

PTP_TIMERWINAPI CreateThreadpoolTimer(

  _In_        PTP_TIMER_CALLBACK pfnti,

  _Inout_opt_ PVOID pv,

  _In_opt_    PTP_CALLBACK_ENVIRON pcbe

);

 

VOIDCALLBACK TimerCallback(

  _Inout_     PTP_CALLBACK_INSTANCE Instance,

  _Inout_opt_ PVOID Context,

  _Inout_     PTP_TIMER Timer

);

 

SetThreadpoolTimer

 

VOIDWINAPI SetThreadpoolTimer(

  _Inout_  PTP_TIMER pti,

  _In_opt_ PFILETIME pftDueTime,

  _In_     DWORD msPeriod,

  _In_opt_ DWORD msWindowLength

);

 

IsThreadpoolTimerSet

 

BOOLWINAPI IsThreadpoolTimerSet(

  _Inout_ PTP_TIMER pti

);

 

WaitForThreadpoolTimerCallbacks

 

VOIDWINAPI WaitForThreadpoolTimerCallbacks(

  _Inout_ PTP_TIMER pti,

  _In_    BOOL fCancelPendingCallbacks

);

 

CloseThreadpoolTimer

 

VOIDWINAPI CloseThreadpoolTimer(

  _Inout_ PTP_TIMER pti

);

 

同样以一个简单的例子说明使用情景:

 

VOID CALLBACK

MyTimerCallback(PTP_CALLBACK_INSTANCE
Instance, PVOID
Parameter,PTP_TIMER
Timer)

{

     _tprintf(_T("MyTimerCallback:timer has fired.\n"));

}

int main(void)

{

     BOOL
ret
;

     FILETIMEFileDueTime;

     ULARGE_INTEGERulDueTime;

     // Create a timerwith the same callback environment.

     PTP_TIMERtimer =
NULL;

     PTP_TIMER_CALLBACKtimercallback =
MyTimerCallback;

     timer =
CreateThreadpoolTimer
(timercallback,NULL,NULL);

     if (NULL ==
timer)

{

         _tprintf(_T("CreateThreadpoolTimerfailed. LastError: %u\n"),

              GetLastError());

     }

 

     // Set the timerto fire in one second.

     ulDueTime.QuadPart = (ULONGLONG)-(1 * 10 * 1000 * 1000);

     FileDueTime.dwHighDateTime =
ulDueTime.HighPart;

     FileDueTime.dwLowDateTime =
ulDueTime.LowPart;

 

     ret =
IsThreadpoolTimerSet
(timer);

     SetThreadpoolTimer(timer,&FileDueTime,0,0);

 

     ret =
IsThreadpoolTimerSet
(timer);

     Sleep(5000);

 

     WaitForThreadpoolTimerCallbacks(timer,FALSE);

     CloseThreadpoolTimer(timer);

     return 0;

}

当内核对象触发的时候调用一个函数

         这种情况是通过在线程池中创建一个等待Event发生的线程,异步完成工作的情景。

CreateThreadpoolWait

SetThreadpoolWait

WaitForThreadpoolWaitCallbacks

CloseThreadpoolWait

 

同样以例子说明情景:

VOID CALLBACK

MyWaitCallback(

                PTP_CALLBACK_INSTANCE
Instance,

                PVOID                
Parameter,

                PTP_WAIT             
Wait,

                TP_WAIT_RESULT       
WaitResult

                )

{

     // Do somethingwhen the wait is over.

     _tprintf(_T("MyWaitCallback:wait is over.\n"));

}

int main(
void)

{

     PTP_WAITWait =
NULL;

     PTP_WAIT_CALLBACKwaitcallback =
MyWaitCallback;

     HANDLE
hEvent
= NULL;

     UINT
i
= 0;

     UINT
rollback
= 0;

 

     // Create anauto-reset event.

     hEvent =CreateEvent(NULL,FALSE,
FALSE,NULL);

     if (NULL ==
hEvent)

{

         // Error Handling

         return;

     }

 

     Wait =
CreateThreadpoolWait
(waitcallback,NULL,NULL);

     if(NULL ==
Wait)

{

         _tprintf(_T("CreateThreadpoolWaitfailed. LastError: %u\n"),

              GetLastError());

         return
-1
;

     }

     // Need tore-register the event with the wait object

     // each timebefore signaling the event to trigger the wait callback.

     for (i = 0;
i <5; i ++)

{

         SetThreadpoolWait(Wait, hEvent, NULL);

         SetEvent(hEvent);

         // Delay forthe waiter thread to act if necessary.

         Sleep(500);

         // Block hereuntil the callback function is done executing.

         WaitForThreadpoolWaitCallbacks(Wait,FALSE);

     }

}   

 

当异步I/O请求完成的时候调用一个函数

CreateThreadpoolIo

StartThreadpoolIo

WaitForThreadpoolIoCallbacks

CancelThreadpoolIo

CloseThreadpoolIo

 

VOIDCALLBACK IoCompletionCallback(

  _Inout_     PTP_CALLBACK_INSTANCE Instance,

  _Inout_opt_ PVOID Context,

  _Inout_opt_ PVOID Overlapped,

  _In_        ULONG IoResult,

  _In_        ULONG_PTR NumberOfBytesTransferred,

  _Inout_     PTP_IO Io

);

 

目前我无法正确使用这个系列函数,有待后续学习后修改。以下是不能调用回调函数的代码,问题还没查清楚。

 

 

VOID
CALLBACK
WriteIoCompletionCallback(

                                       
_Inout_
      PTP_CALLBACK_INSTANCEInstance,

                                       
_Inout_opt_
  PVOID
Context
,

                                       
_Inout_opt_
  PVOID
Overlapped
,

                                       
_In_
         ULONGIoResult,

                                       
_In_
         ULONG_PTRNumberOfBytesTransferred,

                                       
_Inout_
      PTP_IOIo

                                        )

{

     _tprintf(_T("WriteIoCompletionCallbackcalling"));

     return ;

}

int main(void)

{

     TCHAR
readfilename
[] = _T("d:\\test\\test.txt");

     TCHAR
writefilename
[] = _T("d:\\test\\writetest.txt");

     PTP_WIN32_IO_CALLBACKreadcallback =
ReadIoCompletionCallback;

     PTP_WIN32_IO_CALLBACKwritecallback =
WriteIoCompletionCallback;

 

     // 以OVERLAPPED方式打开源文件,以备读出

     HANDLE
hFileRead
= CreateFile(readfilename,

         GENERIC_READ,

         FILE_SHARE_READ,

         NULL,

         OPEN_EXISTING,

         FILE_FLAG_NO_BUFFERING|FILE_FLAG_OVERLAPPED,

         NULL);

 

     // 以OVERLAPPED方式打目标文件,以备写入

     HANDLE
hFileWrite
= CreateFile(writefilename,

         GENERIC_WRITE,

         FILE_SHARE_READ|FILE_SHARE_WRITE,

         NULL,

         CREATE_ALWAYS,

         FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING,NULL);

 

     PTP_IO
readThreadPool
= CreateThreadpoolIo(hFileRead,readcallback,NULL,NULL);

     StartThreadpoolIo(readThreadPool);

 

     //PTP_IOwriteThreadPool = CreateThreadpoolIo(hFileWrite,writecallback,NULL,NULL);

     //StartThreadpoolIo(writeThreadPool);

 

     PVOID
pvData
= VirtualAlloc(NULL,1024,MEM_COMMIT,PAGE_READWRITE);

     OVERLAPPEDoverlapped;

     overlapped.Internal =
overlapped.InternalHigh = 0;

     overlapped.Offset =
overlapped.OffsetHigh = 0;

     ::ReadFile(hFileRead,pvData,1024,NULL,&overlapped);

 

     Sleep(30000);

     WaitForThreadpoolIoCallbacks(readThreadPool,FALSE);

     //WaitForThreadpoolIoCallbacks(writeThreadPool,FALSE);

 

     return 0;

}

 

抱歉!评论已关闭.