我正在尝试 Windows 重叠 IO,但我似乎无法让它异步工作。我已经编译并运行了下面的程序,但它从不打印任何内容,只是默默地完成。我发现小读取可以成为同步,这就是为什么我故意选择读取 512MB。
const DWORD Size = 1<<29; // 512MB
char* Buffer = (char*)malloc(Size);
DWORD BytesRead;
OVERLAPPED Overlapped;
memset(&Overlapped, 0, sizeof(Overlapped));
HANDLE File = CreateFile("BigFile", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
assert(File!=INVALID_HANDLE_VALUE);
DWORD Result = ReadFileEx(File, Buffer, Size, &Overlapped, NULL); // This line takes 150ms according to the debugger
assert(Result);
while(!GetOverlappedResult(File, &Overlapped, &BytesRead, FALSE)) {
printf("Waiting...\n");
}
作为附加信息,我已将代码单步执行到调试器中,并且 Overlapped.InternalHigh
值在 ReadFileEx
调用。
我尝试将 malloc
替换为 VirtualAlloc
,将 ReadFileEx
替换为 ReadFile
,添加 FILE_FLAG_NO_BUFFERING
,并检查读取后 ReadFile
的返回值为 0,并且 GetLastError
将为 ERROR_IO_PENDING
。我尝试使用 RAMMap 来查看文件是否在缓存中,但只有 96KB 存在。
我运行的是带有 8GB RAM 的 Windows 10(版本 1703)。
最佳答案
好的,我已经成功了,这一切都归功于@RbMm。
内存分配没有改变任何东西,但 FILE_FLAG_NO_BUFFERING
标志和 ReadFile
的使用使其工作。我尝试在 ReadFileEx 之后使用 SleepEx,它在 0 处引发了访问冲突,这证明了 @RbMm 的观点,即 lpCompletionRoutine 不是可选的,但强制的。 (对我来说,这意味着我将使用 ReadFile
因为我不需要完成例程)
至于为什么我花了这么长时间才意识到发生了什么:我太信任调试器了,显然闯入调试器并没有停止 IO 进程,这意味着内存仍在OVERLAPPED<内更新
结构,这让我觉得事情是瞬时的。最重要的是,我期望 ReadFile
能够快速返回,但如果我尝试读取 512MB,实际上需要 20 毫秒,当我请求较小的量时,速度要快得多。
谢谢大家的建议:)
为了完整起见,这是工作程序:
const DWORD Size = 1<<20;
char* Buffer = (char*)malloc(Size);
DWORD BytesRead;
OVERLAPPED Overlapped;
memset(&Overlapped, 0, sizeof(Overlapped));
HANDLE File = CreateFile("BigFile", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING|FILE_FLAG_OVERLAPPED, NULL);
assert(File!=INVALID_HANDLE_VALUE);
DWORD Result = ReadFile(File, Buffer, Size, NULL, &Overlapped);
assert(Result==FALSE && GetLastError()==ERROR_IO_PENDING);
while(!GetOverlappedResult(File, &Overlapped, &BytesRead, FALSE)) {
printf("Waiting...\n");
}
关于c - Windows重叠IO实际上是阻塞的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43956446/