come from:http://www.fuzhijie.me/?p=65
一直想弄明白Windows的IO完成端口是什么,这个词语每每出现在我眼前时总是伴随着鲜花和赞美,因此我便将其同许多我从来没搞懂过的东西一起归为神秘一类。这两天一直在看《Windows核心编程》,学到了不少东西,但是同别的英文经典一样,中文版经常让我感觉不知所云,我很不喜欢书中的例子都是用C++来写,并且都有图形界面,这阻碍了初学者理解问题的本质,并不是每个人都熟悉Windows的图形界面编程,Windows的API不仅个数多,许多API参数也非常多,如果仅仅是简单类型也就罢了,许多参数又会是复杂的结构体,相比之下,Unix的系统调用就简洁多了。我打算循序渐进,先学习了下Windows自带的线程池的使用,这个东西实现得挺好的,Linux没有提供等同物。
MSDN中对线程池的使用只给出了一个实例,相关的代码网上少得可怜,我只能对这例子视若珍宝,好好研究了一番,去掉一些旁枝末节,添加点注释吧,就当作是读书札记吧。
《Windows核心编程》中将线程池允许我们做的事情归为四类,分别如下:
情景1:以异步方式调用函数
情景2:每隔一段时间调用一个函数
情景3:在内核对象触发时调用一个函数
情景4:在异步I/O请求完成时调用一个函数
MSDN中的这个例子演示了前三种情景,这三种情景下的回调函数的签名各不一样。原程序中没有给清理组设置回调函数,我写了一个清理回调函数,也只是简单地打印出运行代码的线程号等信息而已。
// // Thread pool wait callback function template // // //注意这三种回调函数的签名,它们都没有返回值 VOID CALLBACK MyWaitCallback( PTP_CALLBACK_INSTANCE Instance, PVOID Parameter, PTP_WAIT Wait, TP_WAIT_RESULT WaitResult ) { printf("%u in MyWaitCallback\n", GetCurrentThreadId()); } // // Thread pool timer callback function template // VOID CALLBACK MyTimerCallback( PTP_CALLBACK_INSTANCE Instance, PVOID Parameter, PTP_TIMER Timer ) { printf("(%u) in MyTimerCallback\n", GetCurrentThreadId()); } // // This is the thread pool work callback function. // The callback demonstrates correct behavior when changing the // state of the thread inside the callback function. // // Any changes to the thread state must be restored to original // before exiting the callback routine. // VOID CALLBACK MyWorkCallback( PTP_CALLBACK_INSTANCE Instance, PVOID Parameter, PTP_WORK Work ) { printf("(%u) in MyWorkCallback\n", GetCurrentThreadId()); } VOID CALLBACK MyCleanupCallback( PVOID pvObjectContext, PVOID pvCleanupContext ) { printf("(%u) in MyCleanupCallback\n", GetCurrentThreadId()); } VOID DemoCleanupPersistentWorkTimer() { BOOL bRet = FALSE; PTP_WORK work = NULL; PTP_TIMER timer = NULL; PTP_POOL pool = NULL; TP_CALLBACK_ENVIRON CallBackEnviron; PTP_CLEANUP_GROUP cleanupgroup = NULL; FILETIME FileDueTime; ULARGE_INTEGER ulDueTime; UINT rollback = 0; printf("(%u)in DemoCleanupPersistentWorkTimer\n", GetCurrentThreadId()); //初始化很重要,否则运行到CreateThreadpoolWork将会出错 //可以在调试模式下看看TP_CALLBACK_ENVIRON结构体的内容 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. // //将最大值和最小值都设置为1,若提交几个工作项时,所有的工作项都由这一个线程完成 //如果可以开启多个线程,可以看到会有好几个线程一起来完成这些工作项 SetThreadpoolThreadMaximum(pool, 1); bRet = SetThreadpoolThreadMinimum(pool, 4); 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 // SetThreadpoolCallbackCleanupGroup(&CallBackEnviron, cleanupgroup, &MyCleanupCallback); // // Create work with the callback environment // //使用的线程池被包含在CallBackEnviron参数中 //如果此处传递NULL进去,将使用一个默认的线程池 work = CreateThreadpoolWork((PTP_WORK_CALLBACK) MyWorkCallback, 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); SubmitThreadpoolWork(work); SubmitThreadpoolWork(work); SubmitThreadpoolWork(work); // // Create a timer with the same callback environment // timer = CreateThreadpoolTimer( (PTP_TIMER_CALLBACK) MyTimerCallback, 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 // //如果为正值,则表示绝对时间,从1600年1月1日开始计算,单位为纳秒 //如果为负值,则表示相对时间,单位为微秒 //两种情况下单位不一样哦。 ulDueTime.QuadPart = (LONGLONG) -(100000000); FileDueTime.dwHighDateTime = ulDueTime.HighPart; FileDueTime.dwLowDateTime = ulDueTime.LowPart; //定时器只触发一次 SetThreadpoolTimer(timer, &FileDueTime, 0, 0); // // Delay for the timer to be fired // //等待线程池中的线程完成定时器中的工作,注意这儿睡眠的值 //要大于上面定时器触发的值,否则就看不到结果了。 Sleep(15000); // // Wait for all callbacks to finish. // CloseThreadpoolCleanupGroupMembers also calls the cleanup // functions for all the individual objects in the specified // cleanup group. // //此时主线程会调用MyCleanupCallback两次,我还没怎么明白清理组的使用方法 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; } VOID DemoNewRegisterWait() { PTP_WAIT Wait = NULL; HANDLE hEvent = NULL; UINT i = 0; UINT rollback = 0; printf("(%u)in DemoNewRegisterWait\n", GetCurrentThreadId()); // // Create an auto-reset event // hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (NULL == hEvent) { // Error Handling return; } rollback = 1; // CreateEvent succeeded Wait = CreateThreadpoolWait((PTP_WAIT_CALLBACK) MyWaitCallback, 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 wait CloseThreadpoolWait(Wait); case 1: // Close event CloseHandle(hEvent); default: break; } return; } int main() { DemoCleanupPersistentWorkTimer(); DemoNewRegisterWait(); return 0; }