多线程编程时用WaitForMultipleObjects函数可以很方便的等待多个线程的退出。但是在一个并行计算pi的程序中出现了一些小问题:为了对比测试不同线程数量的效率,不断加大 线程数,而当线程数大于64时却出现了下图的结果
而且第一行的输出基本上是一运行就输出,而下面的“任意键继续”却等了一会儿才跳出来,显然程序并没有按照设计等到所有线程计算完毕后才继续执行输出pi值。
百度了一下,看到http://www.cnblogs.com/ayanmw/archive/2012/11/13/2767628.html的作者也遇到了和我一样的问题,不过他也没有给出解决方案。
只好乖乖的去msdn找这个函数的用法(http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms687025(v=vs.85).aspx),看到了这样一段话:
To wait on more than MAXIMUM_WAIT_OBJECTS handles, use one of the following methods:
- Create a thread to wait on MAXIMUM_WAIT_OBJECTS handles, then wait on that thread plus the other handles. Use this technique to break the handles into groups ofMAXIMUM_WAIT_OBJECTS.
- Call RegisterWaitForSingleObject to wait on each handle. A wait thread from the thread pool waits onMAXIMUM_WAIT_OBJECTS registered objects and assigns a worker thread after the object is signaled or the time-out interval expires.
看来这个函数确实有个数的限制,最多不能超过MAXIMUM_WAIT_OBJECTS个。这个宏的定义在WinNT.h中
#define MAXIMUM_WAIT_OBJECTS 64 // Maximum number of wait objects
而如果要想等待超过它的数量,按msdn所说有两种方法,都是先要将原来的Objects分成N组,每组不超过MAXIMUM_WAIT_OBJECTS个。方法1是新建N个线程分别等待N组对象,主线程等待这N个线程(若N还是大于MAXIMUM_WAIT_OBJECTS则还可以再次使用这个方法,形成一个树形结构);而方法2是先等待第1组,若第1组超时或收到了信号则继续等待第2组,依次类推顺序等待每一组。
由于第二种方法相对实现比较简单,我选择了这种方法
//************************************
// @Method: SyncWaitForMultipleObjs
// Access: public
// Returns: Same as WaitForMultipleObjects.
// Parameter: handles : An array of object handles to wait.
// Parameter: count : The count of handles.
// brief: Synchronize waiting for all objects signaled.synchronize
//************************************
DWORD ITS_Router::SyncWaitForMultipleObjs(HANDLE * handles, size_t count)
{
int waitNumbers = count / MAXIMUM_WAIT_OBJECTS + 1;
DWORD dRes = 0;
DWORD nCount = 0;
for (int i = 0; i < waitNumbers; ++i)
{
nCount = (i == waitNumbers-1)?(count - i*MAXIMUM_WAIT_OBJECTS):MAXIMUM_WAIT_OBJECTS;
dRes = WaitForMultipleObjects(nCount, handles+i*MAXIMUM_WAIT_OBJECTS, FALSE, 100);
if (dRes == WAIT_TIMEOUT || dRes == WAIT_FAILED)
{
if (nCount < MAXIMUM_WAIT_OBJECTS)
{
return dRes;
}
continue;
}
else
{
return dRes+i*MAXIMUM_WAIT_OBJECTS;
}
}
return dRes;
}