1

今天我了解到我可以调用CreateIoCompletionPort()然后将返回的内容传递HANDLEWaitForSingleObject()

#include <Windows.h>

int main()
{
    HANDLE h = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
    auto bRes = PostQueuedCompletionStatus(h, 1, 2, 0);
    if (!bRes) {
        abort();
    }

    auto dwRes = WaitForSingleObject(h, INFINITE);
    if (dwRes != WAIT_OBJECT_0){
        abort();
    }

    LPOVERLAPPED pOvr;
    DWORD cb;
    ULONG_PTR key;
    bRes = GetQueuedCompletionStatus(
        h, &cb, &key, &pOvr, INFINITE); // <-- returns 1, 2, nullptr

    if (!bRes) {
        abort();
    }

    dwRes = WaitForSingleObject(h, INFINITE); // <-- blocks here
    return 0;
}

它在我的 Windows 10 机器上按预期工作。

这种行为是已知的、合法的或记录在案的吗?我找不到任何关于它的信息。

4

2 回答 2

4

如果您阅读WaitForSingleObject()文档,则 I/O 完成端口不是允许的句柄类型:

WaitForSingleObject函数可以等待以下对象:

  • 变更通知
  • 控制台输入
  • 事件
  • 内存资源通知
  • 互斥体
  • 过程
  • 信号
  • 线
  • 等待定时器

要等待完成事件到达端口,您必须将句柄传递给GetQueuedCompletionStatus()它自己并让它阻塞,直到事件到达或发生超时。

#include <Windows.h>

int main()
{
    HANDLE h = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
    auto bRes = PostQueuedCompletionStatus(h, 1, 2, 0);
    if (!bRes) {
        abort();
    }

    LPOVERLAPPED pOvr;
    DWORD cb;
    ULONG_PTR key;
    bRes = GetQueuedCompletionStatus(
        h, &cb, &key, &pOvr, INFINITE); // <-- returns 1, 2, nullptr

    if (!bRes) {
        abort();
    }

    bRes = GetQueuedCompletionStatus(
        h, &cb, &key, &pOvr, INFINITE); // <-- blocks here

    return 0;
}
于 2016-09-20T20:14:04.227 回答
2

概括:

  • 不要这样做。有关如何正确使用完成端口的信息,请参阅 Remy Lebeau 的回答和 MSDN。
  • 这种滥用完成端口的行为不仅没有记录,而且不可靠。行为因 Windows 10 版本而异。
  • 完成端口可能是内核中等待的合法对象,因为支持完成端口的 KQUEUE 具有 DISPATCHER_HEADER。
于 2016-09-20T22:18:22.487 回答