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

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


你可能感兴趣的:(c++)