警报时GetQueuedCompletionStatusEx行为

时间:2013-09-09 03:18:52

标签: winapi asynchronous iocp io-completion-ports

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

  

当呼叫进入可警告的等待状态且用户APC为   可以发送的返回值   GetQueuedCompletionStatusEx为TRUE,ulEntriesRemoved为非零   你的OVERLAPPED_ENTRY的'包'是不受影响的。所以,如果你确保这一点   你所有的OVERLAPPED_ENTRY都有一个已知的唯一值   lpOverlapped成员,在调用API之前,您可以更轻松地完成   检测已删除的条目是APC还是I / O完成数据包   通过检查lpOverlapped的魔法值。

为什么我需要检查所有OVERLAPPED_ENTRY而不仅仅是第一个?不会GetQueuedCompletionStatusEx()总是按顺序填充输出数组,因此我应该只检查第一个而不是遍历整个数组(或至少达到ulEntriesRemoved)?此外,假设此函数同时将多个完成端口条目出列,是否可以保证它永远不会返回警报和一个或多个完成条目?考虑到评论中的注释,ulEntriesRemoved在警报期间将非零,我特别关注这种可能性。即使页面上的注释进一步提到“如果队列中有任何I / O完成数据包,也不会调度用户APC”,也许这个用户只测试了在用户警报之前排队的任何完成条目

假设系统将两个用户警报的混合排队到线程和完成端口条目,然后线程运行GetQueuedCompletionStatusEx()。从文档中,我无法确定该函数是否使此调用中的所有完成条目出列,然后每个后续调用一个用户警报(假设没有更多的完成条目排队)。在给出文档的情况下,这似乎是最可能的情况,但我不想做出可能会出错的假设...

1 个答案:

答案 0 :(得分:2)

当用户APC执行时,

AFAIK,GetQueuedCompletionStatusEx返回FALSE。并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;
}