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