Winapi 发出警报时GetQueuedCompletionStatusEx行为

Winapi 发出警报时GetQueuedCompletionStatusEx行为,winapi,asynchronous,iocp,io-completion-ports,Winapi,Asynchronous,Iocp,Io Completion Ports,我将fAlertable设置为TRUE时使用此函数,因为我在框架中使用用户警报作为通用线程中断机制。根据MSDN页面上对该功能的评论 当呼叫进入可报警等待状态且用户APC被激活时 可用于分派的返回值 GetQueuedCompletionStatusEx为TRUE,ulEntriesRemoved为非零且 您的重叠入口“包”未被触及。所以如果你保证 您所有的重叠项都有一个已知的唯一值集用于它们的 lpOverlapped成员,在调用API之前,您可以更轻松地 检测删除的条目是APC还是I/O完成

我将fAlertable设置为TRUE时使用此函数,因为我在框架中使用用户警报作为通用线程中断机制。根据MSDN页面上对该功能的评论

当呼叫进入可报警等待状态且用户APC被激活时 可用于分派的返回值 GetQueuedCompletionStatusEx为TRUE,ulEntriesRemoved为非零且 您的重叠入口“包”未被触及。所以如果你保证 您所有的重叠项都有一个已知的唯一值集用于它们的 lpOverlapped成员,在调用API之前,您可以更轻松地 检测删除的条目是APC还是I/O完成数据包 通过检查lpOverlapped以获得该神奇值

为什么我需要检查所有重叠的入口,而不仅仅是第一个?GetQueuedCompletionStatusEx()是否总是按顺序填充输出数组,因此我应该只检查第一个数组,而不是在整个数组上循环(或者至少循环到ulEntriesRemoved)?此外,鉴于此函数同时将多个完成端口条目出列,是否保证它永远不会同时返回警报和一个或多个完成条目?我特别担心这种可能性,因为评论中提到,在警报期间,ulEntriesRemoved将不为零。尽管页面上的注释进一步提到“如果队列中存在任何I/O完成数据包,则不会调度用户APC”,但可能该用户仅针对在用户警报之前排队的任何完成条目进行测试


假设系统以对线程和完成端口项的用户警报的某种混合方式排队,那么线程将运行GetQueuedCompletionStatusEx()。从文档中,我无法确定函数是否将此调用中的所有完成项都出列,然后每次后续调用都会发出一个用户警报(假设没有更多的完成项排队)。考虑到文档,这似乎是最有可能的情况,但我不想做一个可能会被证明是错误的假设…

AFAIK,
GetQueuedCompletionStatusEx
return
FALSE
当用户APC被执行时。和
GetLastError()
返回
等待IO完成
。因此,当用户APC被执行时,它将永远不会将任何完成数据包出列

这是我的代码,非常适合我

if(!::GetQueuedCompletionStatusEx(m_hIoCompletionPort、CompletionPackets、uCompletionPacketsToDequeue和uCompletionPacketsRemoved、dwTimeToSleep、TRUE))
{
DWORD dwError=::GetLastError();
if(dwError==等待IO完成)
{
//用户终止实例。
ATLASSERT(m_bl);
hrResult=S_OK;
打破
}
else if(dwError!=错误\u超时)
{
hrResult=HRESULT\u FROM\u WIN32(dwError);
打破
}
//一个或多个计时器已过。
ATLASSERT(m_Timers.GetCount()!=0);
uCompletionPacketsRemoved=0;
}

对。这是Win32 API中出现的两种“虚假唤醒”情况之一,通常不会出现这种情况。更令人困惑的是,WAIT_IO_COMPLETION是与ERROR_EXE_MARKED_INVALID相同的数字,当您查找返回代码的含义时,这是一个惊喜。