Windows 重叠的 IO 实际上是阻塞的
Windows overlapped IO actually blocks
我正在尝试 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
调用期间得到更新(与 Size
具有相同的值)。
我尝试将 malloc
替换为 VirtualAlloc
,将 ReadFileEx
替换为 ReadFile
,添加 FILE_FLAG_NO_BUFFERING
,并检查了 return ReadFile
的值为 0,读取后 GetLastError
的值为 ERROR_IO_PENDING
。我试过使用 RAMMap 查看文件是否在缓存中,但只有 96KB 在那里。
我是 运行宁 Windows 10(版本 1703),内存为 8GB。
好的,我已经开始工作了,多亏了@RbMm。
除了 FILE_FLAG_NO_BUFFERING
标志和 ReadFile
的使用外,内存分配没有改变任何东西。我尝试在 ReadFileEx
之后使用 SleepEx
,它在 0 处引发了访问冲突,这证明了@RbMm 的观点,即 lpCompletionRoutine
不是可选的,而是强制性的。 (对我来说这意味着我要使用 ReadFile
因为我不想要完成例程)
至于为什么我花了这么长时间才意识到发生了什么:我太相信调试器了,显然闯入调试器并没有停止 IO 进程,这意味着内存仍在 OVERLAPPED
结构,这让我觉得事情是瞬时的。最重要的是,我预计 ReadFile
会很快达到 return,但如果我尝试读取 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");
}
我正在尝试 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
调用期间得到更新(与 Size
具有相同的值)。
我尝试将 malloc
替换为 VirtualAlloc
,将 ReadFileEx
替换为 ReadFile
,添加 FILE_FLAG_NO_BUFFERING
,并检查了 return ReadFile
的值为 0,读取后 GetLastError
的值为 ERROR_IO_PENDING
。我试过使用 RAMMap 查看文件是否在缓存中,但只有 96KB 在那里。
我是 运行宁 Windows 10(版本 1703),内存为 8GB。
好的,我已经开始工作了,多亏了@RbMm。
除了 FILE_FLAG_NO_BUFFERING
标志和 ReadFile
的使用外,内存分配没有改变任何东西。我尝试在 ReadFileEx
之后使用 SleepEx
,它在 0 处引发了访问冲突,这证明了@RbMm 的观点,即 lpCompletionRoutine
不是可选的,而是强制性的。 (对我来说这意味着我要使用 ReadFile
因为我不想要完成例程)
至于为什么我花了这么长时间才意识到发生了什么:我太相信调试器了,显然闯入调试器并没有停止 IO 进程,这意味着内存仍在 OVERLAPPED
结构,这让我觉得事情是瞬时的。最重要的是,我预计 ReadFile
会很快达到 return,但如果我尝试读取 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");
}