Windows 核心编程 11 windows 线程池

来源:互联网 发布:中世纪2优化大百科 编辑:程序博客网 时间:2024/05/21 23:31
Windows 线程池
本节内容有:

1 以异步方式调用函数

windows 线程池新的线程池函数有异步方式的函数原型
VOID NTAPI SimpleCallBack(PTP_CALLBACK_INSTANCE pInstance,PVOID pvContext);
提交一个请求 调用成功返回TRUE,失败返回FALSE
BOOL TrySubmitThreadpoolCallback(PTP_SIMPLE_CALLBACK pfnCallBack,PVOID pvContext,PTP_CALLBACK_ENVIRON pcbe);
创建一个工作项
PTP_WORD CreateThreadpoolWork(PTP_WORD_CALLBACK pfnwordHandler,PVOID PVcontxt,PTP_callBack_Environ pcbe);
工作项的回调函数
VOID CallBack wordCallBack(PTP_CALLBACK_INSTANCE Instance,PVOID Context,ptp_word word);
向线程池提交一个请求void SubmitThreadpoolword(PTP_WORD pword);
取消已经提交的工作项或者将自己挂起void WaitforThreadpoolWordCallbacks(PTP_WORD Pword,BOOL bCancelPendingCallbacks);
不需要一个工作项时调用
void CloseThreadpoolWord(PTP_WORD pwk);
异步函数的代码在最下面

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

 有时应用程序需要在某些时间执行某些任务,windos 提供了可等待的计时器内核对象,它使我们很容易就能够得到一个基于时间的通知。
我们可以使用线程池函数来管理可等待计时器,包括重置和等待下一次触发。
为了将一个工作项安排在某个时间执行,我们必须定义一个回调函数,函数声明如下:
VOID CALLBACK TimeoutCallBack(PTP_CALLBACK_INSTANCE pInstance,   回调函数终止操作讲解
PVOID pvContext,  下面函数传过来的
PTP_TIMER pTimer); 下面函数的返回值
然后调用下面的函数通知线程池应该在何时调用我们的函数:
PTP_TIMER CreateThreadpoolTimer(
PTP_TIMER_CALLBACK pfnTimerCallBack,
PVOID pvcontext,
PTP_CALLBACK_ENVIRON pcbe);
第一个参数是函数指针,第2个参数是传递给回调函数的值,参数3 后面讲
当我们想要向线程池注册计时器的时候,应该调用SetThreadpoolTimer函数:
VOIDWINAPISetThreadpoolTimer(    
__inout  PTP_TIMER pti,   
 __in_opt PFILETIME pftDueTime,
    __in     DWORD     msPeriod,  
  __in_opt DWORD     msWindowLength    );
参数 pti 用来标识CreateThreadpoolTimer返回的TP_TIMER 对象.
参数ptfDueTime 表示第一次调用回调函数应该是什么时候,我们可以传一个负值(微妙为单位)来指定相对时间. 该时间相对于SetThreadpoolTimer的时间,-1是一个特例,表示
立即开始。  为了指定一个绝对时间,应该为正值,100纳秒为单位,从1600年1月1日算起.
参数 msPeriod 表示如果只想触发一次,传0即可,如果不传0,单位是微秒。表示第一次调用以后,以后按这个时间循环调用.
参数 mswindoLength  表示增加一个随机性,如果有多个定时器也冲突。
在设置了计时器之后,我们还可以通过调用SetThreadpoolTimer 并在pti参数中传入以前设置的计时器指针,来对已有的计时器修改
我们传入pftDueTime 为NULL时,这等于告诉线程池停止调用我们的TimerCallBack函数.这不失为一种将计时器暂停但又不必销毁计时器对象的好办法,尤其在回调函数内部,更是如此。
IsThreadpoolTimerSet 来确定某个计时器是否被设置(pftDuetime不为NULL);
WINBASEAPI BOOL WINAPI IsThreadpoolTimerSet( __inout PTP_TIMER pti )
来让线程等待一个定时器完成调用下面函数
WaitForThreadpoolTimerCallbacks();
CloseThreadpoolTimer();函数来释放计时器的内存资源,他们的前面介绍的都一样,如异步函数调用.
下面介绍线程池计时器的使用:见最下 Timed Message Box

3 在内核对象触发时调用一个函数

首先编写一个符合下面的函数原型:
VOID CALLBACK WaitCallback(PTP_CALLBACK_INSTANCE pInstance,PTP_WAIT Wait,TP_WAIT_RESULT WaitResult);】
然后通过调用CreateThreadpoolWait 
来创建一个线程池等待对象
PTP_WAIT WINAPI CreateThreadpoolWait(    __in        PTP_WAIT_CALLBACK    pfnwa,  
  __inout_opt PVOID                pv,  
  __in_opt    PTP_CALLBACK_ENVIRON pcbe    );
当我们创建完成后,我们调用下面的函数来将一个内核对象绑定到这个线程池:
VOID WINAPI SetThreadpoolWait(  
  __inout  PTP_WAIT  pwa,  创建一个等待对象  
  __in_opt HANDLE    h,     需要等待的内核对象  
  __in_opt PFILETIME pftTimeout 表示最长花多少时间等待 0表示不等待,负值表示相对时间正值表示绝对时间,NULL表示一直等下去    );
当内核对象触发或者等待超时,那么线程池中的某个线程会调用我们的回调函数,返回值有3个类型。
WAIT_OBJECT_0WAIT_TIMEOUTWAIT_ABANDONED_0
waitForThreadpoolWaitCallbacks函数来等待一个等待项完成
CloseThreadpoolWait函数来释放一个等待项
线程池的内核对象触发代码在最下面:

4 在异步IO请求完成时调用一个函数

CreateThreadpoolIo来创建一个IO线程池

5 回调函数的终止操作

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Windows 核心编程全部源代码在这个链接上:http://download.csdn.net/detail/woleiwei/5716243
//异步函数的代码
第11章 代码 11-Batch
/******************************************************************************Module:  Batch.cppNotices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre******************************************************************************/#include "..\CommonFiles\CmnHdr.h"     /* See Appendix A. */#include <Windowsx.h>#include <WinBase.h>#include <WinNT.h>// C RunTime Header Files#include <stdlib.h>#include <malloc.h>#include <memory.h>#include <tchar.h>#include <strsafe.h>#include "Batch.h"//////////////////////////////////////////////////////////////////////////////// Global variablesHWND     g_hDlg = NULL;//窗口句柄PTP_WORK g_pWorkItem = NULL;//工作项volatile LONG g_nCurrentTask = 0;//当前工作项数量// Global definitions#define WM_APP_COMPLETED (WM_APP+123)//////////////////////////////////////////////////////////////////////////////void AddMessage(LPCTSTR szMsg) {   HWND hListBox = GetDlgItem(g_hDlg, IDC_LB_STATUS);   ListBox_SetCurSel(hListBox, ListBox_AddString(hListBox, szMsg));}//////////////////////////////////////////////////////////////////////////////void NTAPI TaskHandler(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work) {//返回值是增加后的值   LONG currentTask = InterlockedIncrement(&g_nCurrentTask);   TCHAR szMsg[MAX_PATH];   StringCchPrintf(      szMsg, _countof(szMsg),       TEXT("[%u] Task #%u is starting."), GetCurrentThreadId(), currentTask);   AddMessage(szMsg);   // Simulate a lot of work     Sleep(currentTask * 1000);   StringCchPrintf(      szMsg, _countof(szMsg),       TEXT("[%u] Task #%u is done."), GetCurrentThreadId(), currentTask);   AddMessage(szMsg);   //返回值是减少后的值 最后一个处理完毕了   if (InterlockedDecrement(&g_nCurrentTask) == 0)   {      // Notify the UI thread for completion.      PostMessage(g_hDlg, WM_APP_COMPLETED, 0, (LPARAM)currentTask);   }}//////////////////////////////////////////////////////////////////////////////void OnStartBatch() {   // Disable Start button   Button_Enable(GetDlgItem(g_hDlg, IDC_BTN_START_BATCH), FALSE);   AddMessage(TEXT("----Start a new batch----"));      // Submit 4 tasks by using the same work item   //提交一个工作项用于4个任务   SubmitThreadpoolWork(g_pWorkItem);   SubmitThreadpoolWork(g_pWorkItem);   SubmitThreadpoolWork(g_pWorkItem);   SubmitThreadpoolWork(g_pWorkItem);   AddMessage(TEXT("4 tasks are submitted."));}//////////////////////////////////////////////////////////////////////////////void Dlg_OnCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify) {   switch (id) {      case IDOK:      case IDCANCEL:         EndDialog(hWnd, id);         break;      case IDC_BTN_START_BATCH:         OnStartBatch();         break;   }}BOOL Dlg_OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam) {   // Keep track of main dialog window for error messages   g_hDlg = hWnd;   return(TRUE);}//////////////////////////////////////////////////////////////////////////////INT_PTR WINAPI Dlg_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {   switch (uMsg) {      chHANDLE_DLGMSG(hWnd, WM_INITDIALOG, Dlg_OnInitDialog);      chHANDLE_DLGMSG(hWnd, WM_COMMAND,    Dlg_OnCommand);      case WM_APP_COMPLETED: {         TCHAR szMsg[MAX_PATH+1];         StringCchPrintf(            szMsg, _countof(szMsg),             TEXT("____Task #%u was the last task of the batch____"), lParam);         AddMessage(szMsg);                  // Don't forget to enable the button         Button_Enable(GetDlgItem(hWnd, IDC_BTN_START_BATCH), TRUE);      }      break;   }   return(FALSE);}int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR pCmdLine, int) {   // Create the work item that will be used by all tasks//创建一个工作项用于所有的任务   g_pWorkItem = CreateThreadpoolWork(TaskHandler, NULL, NULL);//参数1 表示回调函数   if (g_pWorkItem == NULL) {      MessageBox(NULL, TEXT("Impossible to create the work item for tasks."),          TEXT(""), MB_ICONSTOP);      return(-1);   }      DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, Dlg_Proc,       _ttoi(pCmdLine));   // Don't forget to delete the work item   CloseThreadpoolWork(g_pWorkItem);   return(0);}//////////////////////////////// End of File /////////////////////////////////


下面代码是 定时器线程池对象
/******************************************************************************Module:  TimedMsgBox.cppNotices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre******************************************************************************/#include "..\CommonFiles\CmnHdr.h"     /* See Appendix A. */#include <tchar.h>#include <StrSafe.h>//////////////////////////////////////////////////////////////////////////////// The caption of our message boxTCHAR g_szCaption[100];// How many seconds we'll display the message boxint g_nSecLeft = 0;// This is STATIC window control ID for a message box// 这个ID是 spy++查看到的#define ID_MSGBOX_STATIC_TEXT    0x0000ffff////////////////////////////////////////////////////////////////////////////////定时器回调函数VOID CALLBACK MsgBoxTimeoutCallback(   PTP_CALLBACK_INSTANCE   pInstance,   PVOID                   pvContext,   PTP_TIMER               pTimer   ){   // NOTE: Due to a thread race condition, it is possible (but very unlikely)   // that the message box will not be created when we get here.//通过标题获得窗口句柄   HWND hwnd = FindWindow(NULL, g_szCaption);   if (hwnd != NULL) {      if (g_nSecLeft == 1) {         // The time is up; force the message box to exit.         EndDialog(hwnd, IDOK);         return;      }      // The window does exist; update the time remaining.      TCHAR szMsg[100];      StringCchPrintf(szMsg, _countof(szMsg),          TEXT("You have %d seconds to respond"), --g_nSecLeft);      SetDlgItemText(hwnd, ID_MSGBOX_STATIC_TEXT, szMsg);   } else {      // The window does not exist yet; do nothing this time.      // We'll try again in another second.     }}int WINAPI _tWinMain(HINSTANCE, HINSTANCE, PTSTR, int) {   _tcscpy_s(g_szCaption, _countof(g_szCaption), TEXT("Timed Message Box"));   // How many seconds we'll give the user to respond   g_nSecLeft = 10;   // Create the threadpool timer object   PTP_TIMER lpTimer =       CreateThreadpoolTimer(MsgBoxTimeoutCallback, NULL, NULL); //第一个参数是 回调函数在前面定义了,后面2个参数没有使用到   if (lpTimer == NULL) {      TCHAR szMsg[MAX_PATH];      StringCchPrintf(szMsg, _countof(szMsg),          TEXT("Impossible to create the timer: %u"), GetLastError());      MessageBox(NULL, szMsg, TEXT("Error"), MB_OK | MB_ICONERROR);      return(-1);   }   // Start the timer in one second to trigger every 1 second   ULARGE_INTEGER ulRelativeStartTime;   ulRelativeStartTime.QuadPart = (LONGLONG) -(10000000);  // start in 1 second 100纳秒为单位 那么 1000 000 0表示1秒   FILETIME ftRelativeStartTime;   ftRelativeStartTime.dwHighDateTime = ulRelativeStartTime.HighPart;   ftRelativeStartTime.dwLowDateTime  = ulRelativeStartTime.LowPart;   SetThreadpoolTimer(      lpTimer,       &ftRelativeStartTime, // 一个单位表示100纳秒 表示调用这个函数以后,回调函数多久第一次执行      1000, // Triggers every 1000 milliseconds  每1秒触发一次      0      );   MessageBox(NULL, TEXT("You have 10 seconds to respond"),       g_szCaption, MB_OK);      // Clean up the timerCloseThreadpoolTimer(lpTimer);//如果不关闭线程池对象,那么回调函数会继续运行,直到进程退出      // Let us know if the user responded or if we timed out   MessageBox(      NULL, (g_nSecLeft == 1) ? TEXT("Timeout") : TEXT("User responded"),       TEXT("Result"), MB_OK);      return(0);}//////////////////////////////// End of File /////////////////////////////////


3  内核对象线程池函数
#include <iostream>#include <windows.h>#include <Winbase.h>#include <tchar.h>VOID CALLBACK MyWaitCallback(   PTP_CALLBACK_INSTANCE Instance,   PVOID                 Parameter,   PTP_WAIT              Wait,   TP_WAIT_RESULT        WaitResult   ){// Instance, Parameter, Wait, and WaitResult not used in this example.UNREFERENCED_PARAMETER(Instance);UNREFERENCED_PARAMETER(Parameter);UNREFERENCED_PARAMETER(Wait);UNREFERENCED_PARAMETER(WaitResult);//// Do something when the wait is over.//_tprintf(_T("MyWaitCallback: wait is over.\n"));}VOID DemoNewRegisterWait(){PTP_WAIT Wait = NULL;PTP_WAIT_CALLBACK waitcallback = MyWaitCallback;HANDLE hEvent = NULL;UINT i = 0;UINT rollback = 0;//// Create an auto-reset event.//hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);if (NULL == hEvent) {// Error Handlingreturn;}rollback = 1; // CreateEvent succeededWait = CreateThreadpoolWait(waitcallback,NULL,NULL);if(NULL == Wait) {_tprintf(_T("CreateThreadpoolWait failed. LastError: %u\n"),GetLastError());goto new_wait_cleanup;}rollback = 2; // CreateThreadpoolWait succeeded//// Need to re-register the event with the wait object// each time before signaling the event to trigger the wait callback.//for (i = 0; i < 5; i ++) {SetThreadpoolWait(Wait,hEvent,NULL);// 参数3 表示花多少时间等待 参数2的内核对象触发SetEvent(hEvent);//// Delay for the waiter thread to act if necessary.//Sleep(500);//// Block here until the callback function is done executing.////表示一直等待工作项完成为止WaitForThreadpoolWaitCallbacks(Wait, FALSE);}new_wait_cleanup:switch (rollback) {case 2:// Unregister the wait by setting the event to NULL.SetThreadpoolWait(Wait, NULL, NULL);//取消等待项和事件关联关系// Close the wait.CloseThreadpoolWait(Wait);case 1:// Close the event.CloseHandle(hEvent);default:break;}return;}int main( void){DemoNewRegisterWait();return 0;}



#include <windows.h>#include <tchar.h>#include <stdio.h>//// Thread pool wait callback function template//VOIDCALLBACKMyWaitCallback(   PTP_CALLBACK_INSTANCE Instance,   PVOID                 Parameter,   PTP_WAIT              Wait,   TP_WAIT_RESULT        WaitResult   ){// Instance, Parameter, Wait, and WaitResult not used in this example.UNREFERENCED_PARAMETER(Instance);UNREFERENCED_PARAMETER(Parameter);UNREFERENCED_PARAMETER(Wait);UNREFERENCED_PARAMETER(WaitResult);//// Do something when the wait is over.//_tprintf(_T("MyWaitCallback: wait is over.\n"));}//// Thread pool timer callback function template//VOIDCALLBACKMyTimerCallback(PTP_CALLBACK_INSTANCE Instance,PVOID                 Parameter,PTP_TIMER             Timer){// Instance, Parameter, and Timer not used in this example.UNREFERENCED_PARAMETER(Instance);UNREFERENCED_PARAMETER(Parameter);UNREFERENCED_PARAMETER(Timer);//// Do something when the timer fires.//_tprintf(_T("MyTimerCallback: timer has fired.\n"));}//// This is the thread pool work callback function.//VOIDCALLBACKMyWorkCallback(   PTP_CALLBACK_INSTANCE Instance,   PVOID                 Parameter,   PTP_WORK              Work   ){// Instance, Parameter, and Work not used in this example.UNREFERENCED_PARAMETER(Instance);UNREFERENCED_PARAMETER(Parameter);UNREFERENCED_PARAMETER(Work);BOOL bRet = FALSE;//// Do something when the work callback is invoked.//{_tprintf(_T("MyWorkCallback: Task performed.\n"));}return;}VOIDDemoCleanupPersistentWorkTimer(){BOOL bRet = FALSE;PTP_WORK work = NULL;// a word ItemPTP_TIMER timer = NULL;PTP_POOL pool = NULL;PTP_WORK_CALLBACK workcallback = MyWorkCallback;PTP_TIMER_CALLBACK timercallback = MyTimerCallback;//回调函数环境变量TP_CALLBACK_ENVIRON CallBackEnviron;PTP_CLEANUP_GROUP cleanupgroup = NULL;FILETIME FileDueTime;ULARGE_INTEGER ulDueTime;UINT rollback = 0;//初始化线程池环境InitializeThreadpoolEnvironment(&CallBackEnviron);//// Create a custom, dedicated(专业) thread pool.//pool = CreateThreadpool(NULL);if (NULL == pool) {_tprintf(_T("CreateThreadpool failed. LastError: %u\n"),GetLastError());goto main_cleanup;}rollback = 1; // pool creation succeeded//// The thread pool is made persistent(固有的) simply by setting// both the minimum and maximum threads to 1.//SetThreadpoolThreadMaximum(pool, 1);bRet = SetThreadpoolThreadMinimum(pool, 1);if (FALSE == bRet) {_tprintf(_T("SetThreadpoolThreadMinimum failed. LastError: %u\n"),GetLastError());goto main_cleanup;}//// Create a cleanup group for this thread pool. 给这个线程池创建一个清理组//cleanupgroup = CreateThreadpoolCleanupGroup();if (NULL == cleanupgroup) {_tprintf(_T("CreateThreadpoolCleanupGroup failed. LastError: %u\n"), GetLastError());goto main_cleanup; }rollback = 2;  // Cleanup group creation succeeded//// Associate(关联) the callback environment with our thread pool.//SetThreadpoolCallbackPool(&CallBackEnviron, pool);//// Associate the cleanup group with our thread pool.// Objects created with the same callback environment// as the cleanup group become members of the cleanup group.//SetThreadpoolCallbackCleanupGroup(&CallBackEnviron,cleanupgroup,NULL);//// Create work with the callback environment.//work = CreateThreadpoolWork(workcallback,NULL, &CallBackEnviron);if (NULL == work) {_tprintf(_T("CreateThreadpoolWork failed. LastError: %u\n"),GetLastError());goto main_cleanup;}rollback = 3;  // Creation of work succeeded//// Submit the work to the pool. Because this was a pre-allocated// work item (using CreateThreadpoolWork), it is guaranteed to execute.//SubmitThreadpoolWork(work);//// Create a timer with the same callback environment.//timer = CreateThreadpoolTimer(timercallback,NULL,&CallBackEnviron);if (NULL == timer) {_tprintf(_T("CreateThreadpoolTimer failed. LastError: %u\n"),GetLastError());goto main_cleanup;}rollback = 4;  // Timer creation succeeded//// Set the timer to fire in one second.//ulDueTime.QuadPart = (ULONGLONG) -(1 * 10 * 1000 * 1000);FileDueTime.dwHighDateTime = ulDueTime.HighPart;FileDueTime.dwLowDateTime  = ulDueTime.LowPart;SetThreadpoolTimer(timer,&FileDueTime,0,0);//// Delay(延迟) for the timer to be fired//Sleep(1500);//// Wait for all callbacks to finish.// CloseThreadpoolCleanupGroupMembers also releases objects// that are members of the cleanup group, so it is not necessary (不必要的)// to call close functions on individual objects // after calling CloseThreadpoolCleanupGroupMembers.//CloseThreadpoolCleanupGroupMembers(cleanupgroup,FALSE,NULL);//// Already cleaned up the work item with the// CloseThreadpoolCleanupGroupMembers, so set rollback to 2.//rollback = 2;goto main_cleanup;main_cleanup://// Clean up any individual pieces manually// Notice the fall-through structure of the switch.// Clean up in reverse order.//switch (rollback) {case 4:case 3:// Clean up the cleanup group members.CloseThreadpoolCleanupGroupMembers(cleanupgroup,FALSE, NULL);case 2:// Clean up the cleanup group.CloseThreadpoolCleanupGroup(cleanupgroup);case 1:// Clean up the pool.CloseThreadpool(pool);default:break;}return;}VOIDDemoNewRegisterWait(){PTP_WAIT Wait = NULL;PTP_WAIT_CALLBACK waitcallback = MyWaitCallback;HANDLE hEvent = NULL;UINT i = 0;UINT rollback = 0;//// Create an auto-reset event.//hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);if (NULL == hEvent) {// Error Handlingreturn;}rollback = 1; // CreateEvent succeededWait = CreateThreadpoolWait(waitcallback,NULL,NULL);if(NULL == Wait) {_tprintf(_T("CreateThreadpoolWait failed. LastError: %u\n"),GetLastError());goto new_wait_cleanup;}rollback = 2; // CreateThreadpoolWait succeeded//// Need to re-register the event with the wait object// each time before signaling the event to trigger the wait callback.//for (i = 0; i < 5; i ++) {SetThreadpoolWait(Wait,hEvent,NULL);SetEvent(hEvent);//// Delay for the waiter thread to act if necessary.//Sleep(500);//// Block here until the callback function is done executing.//WaitForThreadpoolWaitCallbacks(Wait, FALSE);}new_wait_cleanup:switch (rollback) {case 2:// Unregister the wait by setting the event to NULL.SetThreadpoolWait(Wait, NULL, NULL);// Close the wait.CloseThreadpoolWait(Wait);case 1:// Close the event.CloseHandle(hEvent);default:break;}return;}int main( void){DemoNewRegisterWait();DemoCleanupPersistentWorkTimer();getchar();return 0;}



原创粉丝点击