Windows系统线程池+利用windows自带的线程池


一直想弄明白Windows的IO完成端口是什么,这个词语每每出现在我眼前时总是伴随着鲜花和赞美,因此我便将其同许多我从来没搞懂过的东西一起归为神秘一类。这两天一直在看《Windows核心编程》,学到了不少东西,但是同别的英文经典一样,中文版经常让我感觉不知所云,我很不喜欢书中的例子都是用C++来写,并且都有图形界面,这阻碍了初学者理解问题的本质,并不是每个人都熟悉Windows的图形界面编程,Windows的API不仅个数多,许多API参数也非常多,如果仅仅是简单类型也就罢了,许多参数又会是复杂的结构体,相比之下,Unix的系统调用就简洁多了。我打算循序渐进,先学习了下Windows自带的线程池的使用,这个东西实现得挺好的,Linux没有提供等同物。

MSDN中对线程池的使用只给出了一个实例,相关的代码网上少得可怜,我只能对这例子视若珍宝,好好研究了一番,去掉一些旁枝末节,添加点注释吧,就当作是读书札记吧。

《Windows核心编程》中将线程池允许我们做的事情归为四类,分别如下:
情景1:以异步方式调用函数
情景2:每隔一段时间调用一个函数
情景3:在内核对象触发时调用一个函数
情景4:在异步I/O请求完成时调用一个函数

MSDN中的这个例子演示了前三种情景,这三种情景下的回调函数的签名各不一样。原程序中没有给清理组设置回调函数,我写了一个清理回调函数,也只是简单地打印出运行代码的线程号等信息而已。

[cpp]  view plain copy
  1. //  
  2. // Thread pool wait callback function template  
  3. //  
  4. //  
  5. //注意这三种回调函数的签名,它们都没有返回值  
  6. VOID  
  7. CALLBACK  
  8. MyWaitCallback(  
  9.       PTP_CALLBACK_INSTANCE Instance,  
  10.       PVOID                 Parameter,  
  11.       PTP_WAIT              Wait,  
  12.       TP_WAIT_RESULT        WaitResult  
  13.       )  
  14. {  
  15.     printf("%u in MyWaitCallback\n", GetCurrentThreadId());  
  16. }  
  17.    
  18. //  
  19. // Thread pool timer callback function template  
  20. //  
  21. VOID  
  22. CALLBACK  
  23. MyTimerCallback(  
  24.     PTP_CALLBACK_INSTANCE Instance,  
  25.     PVOID                 Parameter,  
  26.     PTP_TIMER             Timer  
  27.     )  
  28. {  
  29.     printf("(%u) in MyTimerCallback\n", GetCurrentThreadId());  
  30. }  
  31.    
  32. //  
  33. // This is the thread pool work callback function.  
  34. // The callback demonstrates correct behavior when changing the  
  35. // state of the thread inside the callback function.  
  36. //  
  37. // Any changes to the thread state must be restored to original  
  38. // before exiting the callback routine.  
  39. //  
  40. VOID  
  41. CALLBACK  
  42. MyWorkCallback(  
  43.       PTP_CALLBACK_INSTANCE Instance,  
  44.       PVOID                 Parameter,  
  45.       PTP_WORK              Work  
  46.       )  
  47. {  
  48.     printf("(%u) in MyWorkCallback\n", GetCurrentThreadId());  
  49. }  
  50.    
  51. VOID  
  52. CALLBACK  
  53. MyCleanupCallback(  
  54.       PVOID pvObjectContext,  
  55.       PVOID pvCleanupContext  
  56.       )  
  57. {  
  58.     printf("(%u) in MyCleanupCallback\n", GetCurrentThreadId());  
  59. }  
  60.    
  61. VOID  
  62. DemoCleanupPersistentWorkTimer()  
  63. {  
  64.     BOOL bRet = FALSE;  
  65.     PTP_WORK work = NULL;  
  66.     PTP_TIMER timer = NULL;  
  67.     PTP_POOL pool = NULL;  
  68.     TP_CALLBACK_ENVIRON CallBackEnviron;  
  69.     PTP_CLEANUP_GROUP cleanupgroup = NULL;  
  70.     FILETIME FileDueTime;  
  71.     ULARGE_INTEGER ulDueTime;  
  72.     UINT rollback = 0;  
  73.    
  74.     printf("(%u)in DemoCleanupPersistentWorkTimer\n", GetCurrentThreadId());  
  75.    
  76.     //初始化很重要,否则运行到CreateThreadpoolWork将会出错  
  77.     //可以在调试模式下看看TP_CALLBACK_ENVIRON结构体的内容  
  78.     InitializeThreadpoolEnvironment(&CallBackEnviron);  
  79.    
  80.     //  
  81.     // Create a custom, dedicated thread pool  
  82.     //  
  83.     pool = CreateThreadpool(NULL);  
  84.    
  85.     if (NULL == pool) {  
  86.         _tprintf(_T("CreateThreadpool failed. LastError: %u\n"),  
  87.         GetLastError());  
  88.         goto main_cleanup;  
  89.     }  
  90.    
  91.     rollback = 1; // pool creation succeeded  
  92.    
  93.     //  
  94.     // The thread pool is made persistent simply by setting  
  95.     // both the minimum and maximum threads to 1.  
  96.     //  
  97.     //将最大值和最小值都设置为1,若提交几个工作项时,所有的工作项都由这一个线程完成  
  98.     //如果可以开启多个线程,可以看到会有好几个线程一起来完成这些工作项  
  99.     SetThreadpoolThreadMaximum(pool, 1);  
  100.    
  101.     bRet = SetThreadpoolThreadMinimum(pool, 4);  
  102.    
  103.     if (FALSE == bRet) {  
  104.         _tprintf(_T("SetThreadpoolThreadMinimum failed. LastError: %u\n"), GetLastError());  
  105.         goto main_cleanup;  
  106.     }  
  107.    
  108.     //  
  109.     // Create a cleanup group for this thread pool  
  110.     //  
  111.     cleanupgroup = CreateThreadpoolCleanupGroup();  
  112.    
  113.     if (NULL == cleanupgroup) {  
  114.         _tprintf(_T("CreateThreadpoolCleanupGroup failed. LastError: %u\n"), GetLastError());  
  115.         goto main_cleanup;  
  116.     }  
  117.    
  118.     rollback = 2;  // Cleanup group creation succeeded  
  119.    
  120.     //  
  121.     // Associate the callback environment with our thread pool  
  122.     //  
  123.     SetThreadpoolCallbackPool(&CallBackEnviron, pool);  
  124.    
  125.     //  
  126.     // Associate the cleanup group with our thread pool  
  127.     //  
  128.     SetThreadpoolCallbackCleanupGroup(&CallBackEnviron,  
  129.         cleanupgroup,  
  130.         &MyCleanupCallback);  
  131.    
  132.     //  
  133.     // Create work with the callback environment  
  134.     //  
  135.     //使用的线程池被包含在CallBackEnviron参数中  
  136.     //如果此处传递NULL进去,将使用一个默认的线程池  
  137.     work = CreateThreadpoolWork((PTP_WORK_CALLBACK) MyWorkCallback,  
  138.         NULL,  
  139.         &CallBackEnviron);  
  140.    
  141.     if (NULL == work) {  
  142.         _tprintf(_T("CreateThreadpoolWork failed. LastError: %u\n"),  
  143.         GetLastError());  
  144.         goto main_cleanup;  
  145.     }  
  146.    
  147.     rollback = 3;  // Creation of work succeeded  
  148.    
  149.     //  
  150.     // Submit the work to the pool. Because this was a pre-allocated  
  151.     // work item (using CreateThreadpoolWork), it is guaranteed  
  152.     // to execute  
  153.     //  
  154.     //可以多提交几个工作项试试看,  
  155.     SubmitThreadpoolWork(work);  
  156.     SubmitThreadpoolWork(work);  
  157.     SubmitThreadpoolWork(work);  
  158.     SubmitThreadpoolWork(work);  
  159.    
  160.     //  
  161.     // Create a timer with the same callback environment  
  162.     //  
  163.     timer = CreateThreadpoolTimer(  
  164.         (PTP_TIMER_CALLBACK) MyTimerCallback,  
  165.         NULL, &CallBackEnviron);  
  166.    
  167.     if (NULL == timer) {  
  168.         _tprintf(_T("CreateThreadpoolTimer failed. LastError: %u\n"),  
  169.         GetLastError());  
  170.         goto main_cleanup;  
  171.     }  
  172.    
  173.     rollback = 4;  // Timer creation succeeded  
  174.    
  175.     //  
  176.     // Set the timer to fire in one second  
  177.     //  
  178.     //如果为正值,则表示绝对时间,从1600年1月1日开始计算,单位为纳秒  
  179.     //如果为负值,则表示相对时间,单位为微秒  
  180.     //两种情况下单位不一样哦。  
  181.     ulDueTime.QuadPart = (LONGLONG) -(100000000);  
  182.     FileDueTime.dwHighDateTime = ulDueTime.HighPart;  
  183.     FileDueTime.dwLowDateTime  = ulDueTime.LowPart;  
  184.    
  185.     //定时器只触发一次  
  186.     SetThreadpoolTimer(timer,  
  187.         &FileDueTime,  
  188.         0,  
  189.         0);  
  190.    
  191.     //  
  192.     // Delay for the timer to be fired  
  193.     //  
  194.     //等待线程池中的线程完成定时器中的工作,注意这儿睡眠的值  
  195.     //要大于上面定时器触发的值,否则就看不到结果了。  
  196.     Sleep(15000);  
  197.    
  198.     //  
  199.     // Wait for all callbacks to finish.  
  200.     // CloseThreadpoolCleanupGroupMembers also calls the cleanup  
  201.     // functions for all the individual objects in the specified  
  202.     // cleanup group.  
  203.     //  
  204.     //此时主线程会调用MyCleanupCallback两次,我还没怎么明白清理组的使用方法  
  205.     CloseThreadpoolCleanupGroupMembers(cleanupgroup,  
  206.         FALSE,  
  207.         NULL);  
  208.    
  209.     //  
  210.     // Already cleaned up the work item with the  
  211.     // CloseThreadpoolCleanupGroupMembers, so set rollback to 2.  
  212.     //  
  213.     rollback = 2;  
  214.     goto main_cleanup;  
  215.    
  216. main_cleanup:  
  217.     //  
  218.     // Clean up any individual pieces manually  
  219.     // Notice the fall through structure of the switch.  
  220.     // Clean up in reverse order.  
  221.     //  
  222.    
  223.     switch (rollback) {  
  224.         case 4:  
  225.         case 3:  
  226.             // Clean up the cleanup group members  
  227.             CloseThreadpoolCleanupGroupMembers(cleanupgroup,  
  228.             FALSE, NULL);  
  229.         case 2:  
  230.             // Clean up the cleanup group  
  231.             CloseThreadpoolCleanupGroup(cleanupgroup);  
  232.    
  233.         case 1:  
  234.             // Clean up the pool  
  235.             CloseThreadpool(pool);  
  236.    
  237.         default:  
  238.             break;  
  239.     }  
  240.    
  241.     return;  
  242. }  
  243.    
  244. VOID  
  245. DemoNewRegisterWait()  
  246. {  
  247.     PTP_WAIT Wait = NULL;  
  248.     HANDLE hEvent = NULL;  
  249.     UINT i = 0;  
  250.     UINT rollback = 0;  
  251.    
  252.     printf("(%u)in DemoNewRegisterWait\n", GetCurrentThreadId());  
  253.    
  254.     //  
  255.     // Create an auto-reset event  
  256.     //  
  257.     hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);  
  258.    
  259.     if (NULL == hEvent) {  
  260.         // Error Handling  
  261.         return;  
  262.     }  
  263.    
  264.     rollback = 1; // CreateEvent succeeded  
  265.    
  266.     Wait = CreateThreadpoolWait((PTP_WAIT_CALLBACK) MyWaitCallback,  
  267.         NULL,  
  268.         NULL);  
  269.    
  270.     if(NULL == Wait) {  
  271.         _tprintf(_T("CreateThreadpoolWait failed. LastError: %u\n"),  
  272.         GetLastError());  
  273.         goto new_wait_cleanup;  
  274.     }  
  275.    
  276.     rollback = 2; // CreateThreadpoolWait succeeded  
  277.    
  278.     //  
  279.     // Need to re-register the event with the wait object  
  280.     // each time before signaling the event to trigger the  
  281.     // wait callback  
  282.     //  
  283.     for (i = 0; i < 5; i ++) {  
  284.         SetThreadpoolWait(Wait,  
  285.         hEvent,  
  286.         NULL);  
  287.    
  288.         //将事业设置成触发态  
  289.         SetEvent(hEvent);  
  290.    
  291.         //  
  292.         // Delay for the waiter thread to act if necessary  
  293.         //  
  294.         Sleep(500);  
  295.    
  296.         //  
  297.         // Block here until the callback function is done executing  
  298.         //  
  299.         //等待回调函数执行完  
  300.         WaitForThreadpoolWaitCallbacks(Wait, FALSE);  
  301.     }  
  302.    
  303. new_wait_cleanup:  
  304.     switch (rollback) {  
  305.         case 2:  
  306.             // Unregister the wait by setting the event to NULL  
  307.             SetThreadpoolWait(Wait, NULL, NULL);  
  308.    
  309.             // Close wait  
  310.             CloseThreadpoolWait(Wait);  
  311.    
  312.         case 1:  
  313.             // Close event  
  314.             CloseHandle(hEvent);  
  315.    
  316.         default:  
  317.         break;  
  318.     }  
  319.     return;  
  320. }  
  321.    
  322. int main()  
  323. {  
  324.     DemoCleanupPersistentWorkTimer();  
  325.    
  326.     DemoNewRegisterWait();  
  327.    
  328.     return 0;  
  329. }  

你可能感兴趣的:(Windows系统线程池+利用windows自带的线程池)