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

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

  • WaitForSingleObject
  • GetOverlappedResult ,bWait = TRUE

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

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

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

我完全赞同Remus Rusanu的 回答 。 还可以创建自己的IOCP和线程池,它将在这个IOCP上侦听,你可以使用或者BindIoCompletionCallback或者CreateThreadpoolIo (从vista开始) – 在这种情况下系统自己创建IOCP和线程池将会监听这个IOCP和什么时候操作完成 – 拨打你的回叫。 这是非常简化的代码与自己的iocp /线程池( 自己的iocp /线程池,我认为只有当你有非常大的计数I / O(比如服务器端的socket 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]或自己实现它的function?