重叠 I/O 的 GetOverlappedResult(bWait=TRUE) 与 WaitForSingleObject()

use*_*142 6 c windows winapi

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

  • WaitForSingleObject
  • GetOverlappedResult与 bWait=TRUE

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

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

RbM*_*bMm 5

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

然而

那么区别是什么呢?为什么我需要 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);
}
Run Code Online (Sandbox Code Playgroud)

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


Rem*_*anu 2

您可以使用其中任何一个,但实际上这不是“正确”的做法。您应该将句柄附加到 IO 完成端口,然后等待完成端口。这样,您就有一个线程池为许多 IO 事件提供服务,因为您可以将多个句柄附加到一个完成端口。我建议阅读《设计高性能应用程序》