2013-09-09 3 views
0

Я использую эту функцию с fAlertable, установленным в TRUE, потому что я использую пользовательские предупреждения как общий механизм прерывания потока в моей структуре. Согласно комментарию на странице MSDN для этой функции,GetQueuedCompletionStatusEx поведение при предупреждении

Когда вызов поступает извещающее состояние ожидания и пользователь APC является доступен для отправки значения возврата GetQueuedCompletionStatusEx ИСТИНЫ, ulEntriesRemoved ненулевой и ваш «пакет» OVERLAPPED_ENTRY не имеет значения. Поэтому, если вы гарантируете, что все ваши OVERLAPPED_ENTRYs имеют известное уникальное значение, установленное для своих членов lpOverlapped, перед тем, как вы вызовете API, вы можете с легкостью определить, является ли удаленная запись APC или пакетом завершения ввода-вывода путем проверки lpOverlapped для этого магического значения.

Зачем мне нужно проверять все OVERLAPPED_ENTRY, а не только на первый? Не будет ли GetQueuedCompletionStatusEx() всегда заполнять выходной массив по порядку, и поэтому я должен проверить только первый, а не цикл по всему массиву (или, по крайней мере, до ulEntriesRemoved)? Более того, учитывая, что эта функция одновременно отменяет несколько записей порта завершения, гарантировано ли это, что никогда не будет возвращено предупреждение и одна или несколько записей о завершении? Я особенно обеспокоен этой возможностью, учитывая примечание в комментарии, что ulEntriesRemoved будет отличным от нуля во время предупреждения. Несмотря на то, что в комментарии на странице далее упоминается, что «Пользовательские APC не будут отправляться, если в очереди есть какие-либо пакеты завершения ввода-вывода». Возможно, этот пользователь тестировал только записи о завершении только в очереди перед предупреждением пользователя ,

Скажите системным очередям в каком-либо соединении обоих оповещений пользователя с данными о потоке и завершении порта, тогда поток запускается GetQueuedCompletionStatusEx(). Из документации я не могу точно сказать, отменяет ли функция все записи завершения в этом вызове, тогда одно оповещение пользователя для каждого последующего вызова (при условии, что больше записей завершения не поставлено в очередь). Казалось бы, это наиболее вероятный случай, учитывая документацию, но я не хочу делать предположение, которое может оказаться неправильным ...

ответ

2

AFAIK, GetQueuedCompletionStatusEx return FALSE, когда пользователь APC был исполнен. И GetLastError() возвращение WAIT_IO_COMPLETION. Таким образом, он никогда не удалит любые пакеты завершения, когда пользователь APC будет выполнен.

Это мой код, который отлично работает для меня.

if (!::GetQueuedCompletionStatusEx(m_hIoCompletionPort, CompletionPackets, uCompletionPacketsToDequeue, &uCompletionPacketsRemoved, dwTimeToSleep, TRUE)) 
{ 
    DWORD dwError = ::GetLastError(); 

    if (dwError == WAIT_IO_COMPLETION) 
    { 
     // User Terminate Instance. 
     ATLASSERT(m_blTerminating); 
     hrResult = S_OK; 
     break; 
    } 
    else if (dwError != ERROR_TIMEOUT) 
    { 
     hrResult = HRESULT_FROM_WIN32(dwError); 
     break; 
    } 

    // One or more Timer has elapsed. 
    ATLASSERT(m_Timers.GetCount() != 0); 
    uCompletionPacketsRemoved = 0; 
} 
+0

Право. Это одна из двух ситуаций «ложного следа», которые встречаются в Win32 API, который обычно не имеет такого типа вещей. Чтобы добавить к путанице, WAIT_IO_COMPLETION - это тот же номер, что и ERROR_EXE_MARKED_INVALID, что приятно удивляет, когда вы смотрите на смысл кода возврата. – Damon

+0

@ Damon Спасибо за эту информацию! – UltimaWeapon