使用WaitForMultipleObjects时注意的问题
今天处理了一个客户端控件的BUG。
这个控件会创建几个线程,每个线程链接服务器下载数据文件及图片等内容。昨天有用户反映在他机器上不能正常获得下载数据,后来经了解用户使用的是Win2K的操作系统,而我在WinXP上反复测试都没有问题。
然后找到一台Win2K的机器进行测试,确实下载存在问题。
通过输出log文件调试,发现在一处调用WaitForMultipleObjects之后,两个系统上的逻辑出现了差异。本来在XP上正常的逻辑,在Win2K上不正常了。
这个地方的逻辑原来是这样写的:
DWORD dwRet = WaitForMultipleObjects(4,pvEvents,TRUE,10000); // 等待所有事件Signal, 10秒超时
if(dwRet == WAIT_OBJECT_0)
{
// 处理正常逻辑
}
else
{
// 处理非正常逻辑
}
其中,参数pvEvents中保存的是4个由CreateEvent创建的事件,每个事件会在一个特定类型的资源下载完成后被Set Signal,而上面这处的意图就是等待这四种资源的下载完成。从日志中看,Win2K系统中进入了else块,而XP中进入了if块。
这时想到的是只能再仔细的查阅MSDN了,而MSDN确实说得很详细,只能怪自己以前没有认真阅读:
====================================================================================
Return Values
If the function succeeds, the return value indicates the event that caused the function to return. It can be one of
the following values.
Return Code Description
-------------------------------------------------------------------------------------
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount – 1)
If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled.
If bWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the lpHandles array index of the object that
satisfied the wait. If more than one object became signalled during the call, this is the array index of the
signalled object with the smallest index value of all the signalled objects.
-------------------------------------------------------------------------------------
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount – 1)
If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled and at least one
of the objects is an abandoned mutex object.
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.
-------------------------------------------------------------------------------------
WAIT_TIMEOUT
The time-out interval elapsed and the conditions specified by the bWaitAll parameter are not satisfied.
====================================================================================
从MSDN中对WaitForMultipleObjects函数返回值的描述中可以看出,返回值有三类,第一类是我使用的情况。这种情况的返回值是
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount – 1)
我在使用中只断章取义的使用了WAIT_OBJECT_0这个返回值,而从后面的括号中内容来看,从WAIT_OBJECT_0 到 (WAIT_OBJECT_0 + nCount – 1)都是有效的值,括号中返回值是和给定要等待的事件数量有关的。比如我等待的是4个事件,在Win2K中WaitForMultipleObjects的返回值就是3,正符合(WAIT_OBJECT_0 + nCount – 1)。而我只判断了WAIT_OBJECT_0 一个返回值显然是不对的。
明白了这一点,把程序修改成:
DWORD dwRet = WaitForMultipleObjects(4,pvEvents,TRUE,10000); // 等待所有事件Signal, 10秒超时
if(dwRet >= WAIT_OBJECT_0
&& dwRet <= (WAIT_ABANDONED_0 + 3))
{
// 处理正常逻辑
}
else
{
// 处理非正常逻辑
}
问题就自然解决了。
这个问题虽然没有理解上的困难,可以说是一个低级错误,但却是我们在编程时容易犯错的一种模式,我们查阅资料时,往往忽略一些细节,断章取义;或者对系统没有透彻理解就盲目着手,从而导致了一些致命的错误。