11.2 Win2008以上的新线程池
(1)传统线程池的优缺点:
①传统Windows线程池调用简单,使用方便(有时只需调用一个API即可)
②这种简单也带来负面问题,如接口过于简单,无法更多去控制线程池的行为。
(2)Windows2008新线程池及API
线程池对象 |
传统API |
Win2008及以上平台新API |
普通任务线程池 |
QueueUserWorkItem |
CreateThreadpoolWork |
TrySubmitThreadpoolWaitCallbacks |
||
SubmitThreadpoolWork |
||
CloseThreadpoolWork |
||
计时器线程池 |
CreateTimerQueue(创建线程池) |
CreateThreadpoolTimer |
CreateTimerQueueTimer(创建计时器) |
SetThreadpoolTimer |
|
ChangeTimerQueueTimer |
IsThreadpoolTimerSet |
|
DeleteTimerQueueTimer |
WaitForThreadpoolTimerCallbacks |
|
DeteTimerQueueEx |
CloseThreadpoolTimer |
|
同步对象等待线程池 |
RegisterWaitForSingleObject |
CreateThreadpoolWait |
UnregisterWaitEx |
SetThreadpoolWait |
|
WaitForThreadpoolWaitCallbacks |
||
CloseThreadpoolWait |
||
完成端口线程池 |
BindIoCompletionCallback |
CreateThreadpoolIo |
StartThreadpoolIo |
||
CancelThreadpoolIo |
||
WaitForThreadpoolIoCallbacks |
||
CloseThreadpoolIo |
(3)新线程池辅助API
功能 |
辅助API |
线程池清理器 |
CreateThreadpoolCleanupGroup |
CloseThreadpoolCleanupGroup |
|
ClosethreadpoolCleanupGroupMembers |
|
线程池控制函数 |
CreateThreadpool |
CloseThreadpool |
|
SetThreadpoolThreadMaximum |
|
SetThreadpoolMinimum |
|
线程池环境设备 |
InitializeThreadpoolEnviroment |
DestroyThreadpoolEnvironment |
|
SetThreadpoolCallbackCleanupGroup |
|
SetThreadCallbackLibrary |
|
SetThreadpoolbackpool |
|
SetThreadpoolCallbackRunsLong |
|
显式设定一个长时间调用的回调线程池函数 |
CallbackMayRunLong |
清理及回调方法 |
DisassociateCurrentThreadFromCallback |
FreeLibraryWhenCallbackReturns |
|
LeaveCriticalSectionWhenCallbackReturns |
|
ReleaseMutexWhenCallbackReturns |
|
ReleaseSemaphoreWhenCallbackReturns |
|
SetEventWhenCallbackReturns |
(3)Win2008新线程池的一般编程模型
11.2.1 以异步方式调用函数
(1)单步使用线程池——TrySubmitThreadpoolCallback函数提交异步函数给线程池
参数 |
描述 |
PTP_SIMPLE_CALLBACK pfnCallback |
回调函数,其原型为: VOID NTAPI SimpleCallback (PTP_CALLBACK_INSTANCE pInstance, //不透明的参数,调用回调函数时,由Windows自动传入,可用于继续传给其他回调终止操作的函数使用,如LeaveCriticalSectionWhenCallbackReturns。。 PVOID pvContext);//其中的pInstanc见“回调函数终止时行为”那部分的内容 |
PVOID pvContext |
回调函数的额外参数。 |
PTP_CALLBACK_ENVIRON pcbe |
回调环境,用来对线程池进行定制的参数。(注意,这个结构体内部与一个线程池关联,该参数为NULL时,会创建默认线程池,否则我们可以用CreateThreadpool来创建一个线程池,并与这个结构体关联起来) |
备注:当为pcbe为NULL时,该函数被调用时系统会在进程中创建一个默认的线程池,并让线程池中的一个线程来调用指定的回调函数。该函数(内部调用PostQueuedCompletionStatus)将一个工作项添加到队列中。 |
(2)两步使用线程池
①CreateThreadpoolWork创建“工作项”。注意与之前所说的那些工作项不同。这里的工作项是个对象,不能简单理解成是一个回调函数。而是关联了回调函数及回调环境的一个对象了!
参数 |
描述 |
PTP_WORK_CALLBACK pfnWorkHandler |
工作项要关联的回调函数,其原型为 VOID CALLBACK WorkCallback( PTP_CALLBACK_INSTNACE,PVOID pvContext,PTP_WORK work); |
PVOID pvContext |
回调函数的额外参数 |
PTP_CALLBACK_ENVIRON pcbe |
回调环境,见《TrySubmitThreadpoolCallback函数》的说明 |
②SubmitThreadpoolWork提交这个工作项给线程池。结束后还可以关闭该工作项。
SubmitThreadpoolWork(PTP_WORK pWork);
【注意】
★WaitForThreadpoolWorkCallbacks(pWork,bCancelPendingCallbacks)取消己提交的工作项或等待工作项处理完成
bCancelPendingCallbacks为FALSE,会等待工作项处理完成,函数再返回。为TRUE时会试图取消pWork这个工作项。
如果用一个PTP_WORK提交了多个工作项,当bCancelPendingCallbacks为FALSE时则会等待所有的己提交的工作项,如果为TRUE只要等待当前正在运行的工作项完成时就返回。
★CloseThreadpoolWork关闭一个工作项
【Batch示例程序】批处理程序
//主程序
/************************************************************************* Module: Batch.cpp Notices: Copyright(c) 2008 Jeffrey Ritcher & Christophe Nasarre *************************************************************************/ #include "....CommonFilesCmnHdr.h" #include "resource.h" #include <tchar.h> #include <strsafe.h> ////////////////////////////////////////////////////////////////////////// //全局变量 HWND g_hDlg = NULL; PTP_WORK g_pWorkItem = NULL;//工作项对象 volatile LONG g_nCurrentTask = 0; //自定义消息 #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 WINAPI TaskHandler(PTP_CALLBACK_INSTANCE pInstance, PVOID pvContext, PTP_WORK pWork){ LONG currentTask = InterlockedIncrement(&g_nCurrentTask); TCHAR szMsg[MAX_PATH]; StringCchPrintf(szMsg, _countof(szMsg), TEXT("线程[%u]:%u号任务开始. "), GetCurrentThreadId(), currentTask); AddMessage(szMsg); //模拟许多的工作 Sleep(currentTask * 1000); StringCchPrintf(szMsg, _countof(szMsg), TEXT("线程[%u]:%u号任务结束. "), GetCurrentThreadId(), currentTask); AddMessage(szMsg); if (InterlockedDecrement(&g_nCurrentTask)==0){ //通知UI线程任务己经完成 PostMessage(g_hDlg, WM_APP_COMPLETED, 0, (LPARAM)currentTask); } } ////////////////////////////////////////////////////////////////////////// void OnStartBatch(){ //禁用“开始”按钮 Button_Enable(GetDlgItem(g_hDlg, IDC_BTN_START_BATCH), FALSE); AddMessage(TEXT("----开始新的批处理----")); //使用同一个工作项对象,提交6个任务 for (int i = 0; i < 6;i++){ SubmitThreadpoolWork(g_pWorkItem); } //SubmitThreadpoolWork(g_pWorkItem); //SubmitThreadpoolWork(g_pWorkItem); //SubmitThreadpoolWork(g_pWorkItem); //SubmitThreadpoolWork(g_pWorkItem); //SubmitThreadpoolWork(g_pWorkItem); } ////////////////////////////////////////////////////////////////////////// BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){ g_hDlg = hwnd; return TRUE; } void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotity){ switch (id) { case IDOK: case IDCANCEL: EndDialog(hwnd, id); break; case IDC_BTN_START_BATCH: OnStartBatch(); break; } } ////////////////////////////////////////////////////////////////////////// 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("----%u号任务是批处理的最后一个任务----"), lParam); AddMessage(szMsg); //启用“开始”按钮 Button_Enable(GetDlgItem(g_hDlg, IDC_BTN_START_BATCH), TRUE); } break; } return FALSE; } ////////////////////////////////////////////////////////////////////////// int APIENTRY _tWinMain(HINSTANCE hInst, HINSTANCE, LPTSTR pCmdLine, int){ //创建用于供所有任务使用的工作项对象(最后一个参数为NULL,使用进程默认的线程池!) g_pWorkItem = CreateThreadpoolWork(TaskHandler, NULL, NULL); if (NULL == g_pWorkItem){ MessageBox(NULL, TEXT("无法创建任务所需的工作项对象"), TEXT(""), MB_ICONSTOP); return -1; } //ttoi,将字符转为整型 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, Dlg_Proc,_ttoi(pCmdLine)); //关闭工作项对象 CloseThreadpoolWork(g_pWorkItem); return 0; }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 11_Batch.rc 使用 // #define IDD_MAIN 101 #define IDC_LB_STATUS 1001 #define IDC_BTN_START_BATCH 1002 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1003 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Batch.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h " END 2 TEXTINCLUDE BEGIN "#include ""winres.h"" " "