最近在做关于多相机同时触发拍摄的项目,需要做到多线程等待同步的功能,但是单独的使用有时候会出现接收不到信号的问题,偶然看到了这篇文章,写的还不错,然后分析了自己的问题,发现了问题所在,分享给大家,可以帮到大家
举个例子:我们需要在一个线程中处理从完成端口、数据库、和可等待定时器来的数据。
WaeeitForMultipleObjects是Windows中的一个功能非常强大的函数,几乎可以等待Windows中的所有的内核对象(关于该函数的描述和例子见MSDN,)。
原型:DWORD WaitForMultipleObjects(
DWORD nCount,
const HANDLE* lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
);
Parameters
nCount
[in] lpHandles指向的数组中的对象句柄数。对象句柄的最大数量为MAXIMUM_WAIT_OBJECTS。此参数不能为零。
lpHandles
[in]一组对象句柄。该数组可以包含不同类型对象的句柄。它可能不包含同一句柄的多个副本。
如果其中一个句柄在等待仍处于暂挂状态时关闭,则该函数的行为未定义。
句柄必须具有SYNCHRONIZE访问权限。
Windows NT/2000/XP: 句柄必须具有同步访问权限。
Windows 95/98/Me:任何句柄都可以是用DuplicateHandle创建的另一个句柄的副本。
bWaitAll
[in] 如果此参数为TRUE,则在lpHandles数组中的所有对象的状态发出信号时,该函数返回。如果为FALSE,则当任何一个对象的状态设置为信号时,该函数返回。在后一种情况下,返回值表示其状态导致函数返回的对象。
dwMilliseconds
[in] 超时间隔,以毫秒为单位。如果指定了非零值,则该函数将一直等到指定的对象发出信号或经过间隔。如果dwMilliseconds为零,则如果未发出指示对象,则该函数不会进入等待状态;它总是立即返回。如果dwMilliseconds是INFINITE,则仅在发出指定对象信号时才返回该函数。
如果函数成功,返回值表示该事件导致该函数返回。这个值可以是下列之一。
WAIT_OBJECT_0到(WAIT_OBJECT_0 + nCount - 1如果bWaitAll为TRUE),则返回值表明所有指定对象的状态信号。
如果bWaitAll为FALSE,则返回值减去不是WAIT_OBJECT_0表示lpHandles数组的对象的满意指数的等待。如果多个对象在通话过程中信号成为,这是与所有的信号对象的最小索引值的信号对象的数组索引。
WAIT_ABANDONED_0至(WAIT_ABANDONED_0 + nCount - 1)如果bWaitAll为TRUE,则返回值表明所有指定对象的状态是触发的,并且至少对象之一,是一个废弃的互斥对象。
If bWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the lpHandles array index of an abandoned mutex object that satisfied the wait
如果bWaitAll为FALSE,则返回值减去WAIT_ABANDONED_0 表示一个废弃的互斥对象在lpHandles数组中的下标,满足等待。
WAIT_TIMEOUTThe超时间隔已过,由bWaitAll参数指定的条件得不到满足。
当WaitForMultipleObjects等到多个内核对象的时候,如果它的bWaitAll 参数设置为false。其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号。如果同时有多个内核对象被触发,这个函数返回的只是其中序号最小的那个。如果为TRUE 则等待所有信号量有效再往下执行。(FALSE 当有其中一个信号量有效时就向下执行)
问题就在这里,我们如何可以获取所有被同时触发的内核对象。一个典型的实现方法就是:用WaitForMultipleObjects等待所有的这些事件。如果完成端口,数据库发过来的数据量非常大,可等待定时器时间也只有几十毫秒。那么这些事件同时触发的几率可以说非常大,我们不希望丢弃任何一个被触发的事件。那么如何能高效地实现这一处理呢?
多个内核对象被触发时,WaitForMultipleObjects选择其中序号最小的返回。而WaitForMultipleObjects它只会改变使它返回的那个内核对象的状态。
这儿又会产生一个问题,如果序号最小的那个对象频繁被触发,那么序号比它大的内核对象将得不到被处理的机会。
为了解决这一问题,可以采用双WaitForMultipleObjects检测机制来实现。见下面的例子:
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
DWORD dwRet = 0;
int nIndex = 0;
while(1)
{
dwRet = WaitForMultipleObjects(nCount,pHandles,false,INFINITE);
switch(dwRet)
{
case WAIT_TIMEOUT: break;
case WAIT_FAILED: return 1;
default:
{
nIndex = dwRet - WAIT_OBJECT_0;
ProcessHanlde(nIndex++); //同时检测其他的事件
while(nIndex < nCount) //nCount事件对象总数
{
dwRet = WaitForMultipleObjects(nCount - nIndex,&pHandles[nIndex],false,0);
switch(dwRet)
{
case WAIT_TIMEOUT:
nIndex = nCount; //退出检测,因为没有被触发的对象了.
break;
case WAIT_FAILED:
return 1;
default:
{
nIndex = nIndex + dwRet - WAIT_OBJECT_0;
ProcessHanlde(nIndex++);
}
break ;
}
}//end-while
}
break;
}
}
return 0;
}