当我在 Win32 api 上以重叠方式打开和读取文件时,我有几种方法来完成 IO 请求,包括等待文件句柄(或重叠结构中的事件)
WaitForSingleObject GetOverlappedResult与 bWait=TRUE这两个函数似乎具有相同的效果:线程停止,直到发出句柄或事件信号,这意味着数据被放置在提供给 的缓冲区中ReadFile。
那么区别是什么呢?为什么我需要GetOverlappedResult?
我完全同意Remus Rusanu 的 回答。也可以创建自己的IOCP和线程池,它将侦听此IOCP,您可以使用 orBindIoCompletionCallback或CreateThreadpoolIo(从 vista 开始) - 在这种情况下,系统自己创建IOCP和线程池,它将侦听此IOCP并在某些操作完成时- 拨打您的回拨电话。与自己的 iocp/线程池相比,这是非常简化的代码(我认为只有当您有非常大的 I/O 数量(例如服务器端的套接字 io)并且需要对性能进行特殊优化时,自己的 iocp/线程池才有意义)
然而
那么区别是什么呢?为什么我需要 GetOverlappedResult
您GetOverlappedResult[Ex]不仅可以看到等待结果,还可以看到
所以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]自己使用或实现它的功能呢?
您可以使用其中任何一个,但实际上这不是“正确”的做法。您应该将句柄附加到 IO 完成端口,然后等待完成端口。这样,您就有一个线程池为许多 IO 事件提供服务,因为您可以将多个句柄附加到一个完成端口。我建议阅读《设计高性能应用程序》。