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;
- }