Я столкнулся с этим ограничением в WaitForMultipleObjects и пришел к выводу, что у меня есть три варианта:
- ВАРИАНТ 1. Измените код на создайте отдельные потоки для вызова WaitForMultipleObjects в пакетном режимеменьше чем MAXIMUM_WAIT_OBJECTS.Я отказался от этой опции, потому что, если уже есть 64+ потоков, борющихся за один и тот же ресурс, я хотел бы избежать создания еще большего количества потоков, если это возможно.
- ОПЦИЯ 2. Повторно внедрить код, используя другую технику (например, IOCP).Я тоже отказался от этого, потому что кодовая база, над которой я работаю, проверена, проверена и стабильна.Кроме того, у меня есть дела поважнее!
- ОПЦИЯ 3. Реализовать функцию, которая разбивает объекты на пакеты, меньшие, чем MAXIMUM_WAIT_OBJECTS, и повторно вызывает WaitForMultipleObjects в одном и том же потоке .
Итак, выбраввариант 3 - вот код, который я реализовал ...
class CtntThread
{
public:
static DWORD WaitForMultipleObjects( DWORD, const HANDLE*, DWORD millisecs );
};
DWORD CtntThread::WaitForMultipleObjects( DWORD count, const HANDLE *pHandles, DWORD millisecs )
{
DWORD retval = WAIT_TIMEOUT;
// Check if objects need to be split up. In theory, the maximum is
// MAXIMUM_WAIT_OBJECTS, but I found this code performs slightly faster
// if the object are broken down in batches smaller than this.
if ( count > 25 )
{
// loop continuously if infinite timeout specified
do
{
// divide the batch of handles in two halves ...
DWORD split = count / 2;
DWORD wait = ( millisecs == INFINITE ? 2000 : millisecs ) / 2;
int random = rand( );
// ... and recurse down both branches in pseudo random order
for ( short branch = 0; branch < 2 && retval == WAIT_TIMEOUT; branch++ )
{
if ( random%2 == branch )
{
// recurse the lower half
retval = CtntThread::WaitForMultipleObjects( split, pHandles, wait );
}
else
{
// recurse the upper half
retval = CtntThread::WaitForMultipleObjects( count-split, pHandles+split, wait );
if ( retval >= WAIT_OBJECT_0 && retval < WAIT_OBJECT_0+split ) retval += split;
}
}
}
while ( millisecs == INFINITE && retval == WAIT_TIMEOUT );
}
else
{
// call the native win32 interface
retval = ::WaitForMultipleObjects( count, pHandles, FALSE, millisecs );
}
// done
return ( retval );
}