【问题标题】:GetOverlappedResult(bWait=TRUE) vs WaitForSingleObject() for overlapped I/OGetOverlappedResult(bWait=TRUE) 与 WaitForSingleObject() 的重叠 I/O
【发布时间】:2017-03-11 23:46:09
【问题描述】:

当我在 Win32 api 上以 OVERLAPPED 方式打开和读取文件时,我有几种方法来完成 IO 请求,包括使用等待文件句柄(或重叠结构中的事件)

  • WaitForSingleObject
  • GetOverlappedResult 与 bWait=TRUE

这两个函数似乎具有相同的效果:线程停止直到处理或事件发出信号,这意味着数据被放置在提供给ReadFile的缓冲区中。

那么,有什么区别呢?为什么我需要GetOverlappedResult

【问题讨论】:

  • 短版:WaitForSingleObject 不会告诉你操作是成功还是失败,如果它碰巧是那种处理的字节数比你要求的少的 I/O,你也不知道。

标签: c windows winapi


【解决方案1】:

我完全同意 Remus Rusanu answer 。也可以创建自己的 IOCP 和线程池,它们将在此 IOCP 上进行监听,您可以使用 BindIoCompletionCallbackCreateThreadpoolIo(从 vista 开始) - 在此案例系统自己创建 IOCP 并且线程池将在此 IOCP 上进行侦听,并且当某些操作完成时 - 调用您的回调。这是非常简化的代码与自己的 iocp/线程池(自己的 iocp/线程池,我认为只有当你有非常大的 I/O 计数(比如服务器端的套接字 io)并且需要对性能进行特殊优化时才有意义实施)

然而

那么,有什么区别呢?为什么我需要 GetOverlappedResult

你怎么能看到GetOverlappedResult[Ex]不仅等待结果,而且

  • 如果操作完成返回给您NumberOfBytesTransferred
  • 如果操作完成并出现错误 NTSTATUS - 将其转换为 win32 错误并设置最后一个错误
  • 如果操作仍然挂起并且您想要等待 - 它选择等待 hFilehEvent

所以GetOverlappedResult[Ex] 做的不仅仅是打电话给WaitForSingleObject

但是自己实现这个 API 并不难。例如

BOOL
WINAPI
MyGetOverlappedResult(
                    _In_ HANDLE hFile,
                    _In_ LPOVERLAPPED lpOverlapped,
                    _Out_ LPDWORD lpNumberOfBytesTransferred,
                    _In_ BOOL bWait
                    )
{
    if ((NTSTATUS)lpOverlapped->Internal == STATUS_PENDING)
    {
        if (!bWait)
        {
            SetLastError(ERROR_IO_INCOMPLETE);
            return FALSE;
        }

        if (lpOverlapped->hEvent)
        {
            hFile = lpOverlapped->hEvent;
        }

        if (WaitForSingleObject(hFile, INFINITE) != WAIT_OBJECT_0)
        {
            return FALSE;
        }
    }
    else
    {
        MemoryBarrier();
    }

    *lpNumberOfBytesTransferred = (ULONG)lpOverlapped->InternalHigh;
    NTSTATUS status = (NTSTATUS)lpOverlapped->Internal;
    if (status)
    {
        RtlNtStatusToDosError(status);
    }
    return NT_SUCCESS(status);
}

那么有什么更好的方法:使用GetOverlappedResult[Ex] 或自己实现它的功能?

【讨论】:

    【解决方案2】:

    您可以使用其中任何一种,但这确实不是“正确”的做法。您应该将句柄附加到 IO 完成端口,然后在完成端口上等待。这样一来,您就有了一个线程池为许多 IO 事件提供服务,因为您可以将多个句柄附加到一个完成端口。我推荐阅读Designing Applications for High Performance

    【讨论】:

    • 谢谢,但我永远不会有超过 2 个 I/O 操作,所以我不确定我是否需要 IO Completion 端口。我了解它们以及其他方法,例如 Alterable IO (APC)。我的问题是关于差异:)
    • @user996142 使用 IO Completion 端口总是比使用 GetOverlappedResult 等待 任何计数 如果 I/O 操作更好,您也可以通过 BindIoCompletionCallback 或 @ 间接使用它987654323@
    • @RbMm 在一般情况下,我 100% 同意 IOCP 将优于重叠 IO。我知道的一个例外是全双工串行 IO。根据msdn.microsoft.com/en-us/library/ff802693.aspx在“读写”部分的“非重叠IO”小节中指出,如果不使用重叠IO,就无法在串口上进行全双工通信。
    • @dgnuff - IOCP 会比重叠 IO 更好 - 重叠 I/O - 这是 异步 I/O。表示文件句柄以异步模式打开 - 带有标志 FILE_FLAG_OVERLAPPED(如果我们使用 CreateFile)或不带有 FILE_SYNCHRONOUS_IO_[NON]ALERT 标志,如果我们使用 Zw api。 IOCP 只能与文件句柄关联,前提是它是 asynchronous(看 1550 行)。所以你的评论不正确。 IOCP 不是 io 类型。这是另一个。并且只能与重叠 IO 一起使用
    猜你喜欢
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    • 2010-09-08
    • 2011-12-04
    • 1970-01-01
    • 2023-03-19
    相关资源
    最近更新 更多