对于重叠的I / O

时间:2017-03-11 23:46:10

标签: c windows winapi

当我在Win32 api上以OVERLAPPED方式打开并读取文件时,我有几种方法可以完成IO请求,包括使用

等待文件句柄(或重叠结构中的事件)
  • WaitForSingleObject
  • GetOverlappedResult,bWait = TRUE

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

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

2 个答案:

答案 0 :(得分:3)

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

然而

  

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

您如何看待GetOverlappedResult[Ex]不仅等待结果,还

  • 如果操作完成,则返回 NumberOfBytesTransferred
  • 如果操作完成但错误 NTSTATUS - 将其转换为win32 错误并设置上一个错误
  • 如果操作仍处于待处理状态且你想要等待 - 它选择等待 hFile hEvent

所以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]或自己实现功能吗?

答案 1 :(得分:2)

你可以使用其中任何一种,但真的不是“正确的”#39;这样做的方式。您应该将句柄附加到IO完成端口,然后等待完成端口。这样,您就有一个服务于许多IO事件的线程池,因为您可以将多个句柄附加到完成端口。我建议阅读Designing Applications for High Performance