根据MSDN,ReadFile
可以通过两种不同的方式读取数据:同步和异步。
我需要第二个。下面的代码演示了OVERLAPPED
struct:
#include <windows.h>
#include <stdio.h>
#include <time.h>
void Read()
{
HANDLE hFile = CreateFileA("c:\\1.avi", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if ( hFile == INVALID_HANDLE_VALUE )
{
printf("Failed to open the file\n");
return;
}
int dataSize = 256 * 1024 * 1024;
char* data = (char*)malloc(dataSize);
memset(data, 0xFF, dataSize);
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
printf("reading: %d\n", time(NULL));
BOOL result = ReadFile(hFile, data, dataSize, NULL, &overlapped);
printf("sent: %d\n", time(NULL));
DWORD bytesRead;
result = GetOverlappedResult(hFile, &overlapped, &bytesRead, TRUE); // wait until completion - returns immediately
printf("done: %d\n", time(NULL));
CloseHandle(hFile);
}
int main()
{
Read();
}
在Windows XP上输出是: 阅读:1296651896 发送:1296651896 完成:1296651899
这意味着ReadFile
没有阻止并在同一时间返回imediatly,而阅读过程持续3秒。这是正常的异步读取。
但在Windows 7和Windows 2008上,我得到以下结果: 阅读:1296661205 发送:1296661209 完成:1296661209。 这是同步阅读的行为。
MSDN表示,异步ReadFile
有时可以表现为同步(例如,当文件被压缩或加密时)。但是这种情况下的返回值应为TRUE且GetLastError()
== NO_ERROR。
在Windows 7上,我得到FALSE和GetLastError()
== ERROR_IO_PENDING。所以WinApi告诉我这是一个异步调用,但是当我看测试时,我发现它不是!
我不是唯一发现此“bug”的人:阅读ReadFile MSDN页面上的评论。
那么解决方案是什么?有人知道吗?在丹尼斯发现这种奇怪行为之后的14个月。
答案 0 :(得分:4)
我不知道“c:\ 1.avi”文件的大小,但是你给Windows的缓冲区大小(256M!)可能足以容纳文件。因此,Windows决定读取整个文件并将其放入缓冲区中。你没有对windows说“我想要异步”,你说“我知道如何处理异步”。
只需将缓冲区大小改为1024,程序就会完全相同,但只读取1024个字节(并返回ERROR_IO_PENDING)。
通常,您执行异步操作是因为您希望在操作期间执行其他操作。请查看此处的示例:Testing for the End of a File,因为它演示了异步ReadFile。如果更改样本的缓冲区并将其设置为较大的值,则其行为应与您的完全相同。
PS:我建议你不要依赖时间样本来检查事物,使用返回代码和事件
答案 1 :(得分:1)
这可能与缓存有关。尝试打开非缓存文件(FILE_FLAG_NO_BUFFERING
)
修改强>
这实际上记录在ReadFile的MSDN文档中:
注意如果打开了文件或设备 用于异步I / O,后续调用 使用ReadFile等函数 处理一般返回 马上,但也可以表现 同步被阻止 执行。有关更多信息,请参阅 http://support.microsoft.com/kb/156932
答案 2 :(得分:1)
根据this,我怀疑它应该在你的情况下返回TRUE。但也可能是Win7 / Win2k8上的完成模式默认设置不同。 尝试使用SetFileCompletionNotificationModes()设置不同的模式。
答案 3 :(得分:1)
您是否尝试使用@Simon Mourier建议的活动?我知道文档说不需要这个事件,但是如果你看到@Simon Mourier提供的链接中的例子,它就是使用一个事件进行异步读取。
答案 4 :(得分:1)
Windows7 / Server2008具有不同的行为来解决GetOverlappedResultEx中可能发生的竞争条件。当您为这些操作系统编译时,Windows会检测到此并使用不同的行为。我发现这个邪恶的混乱。
这是一个链接: http://msdn.microsoft.com/en-us/library/dd371711(VS.85).aspx
我确定你过去曾多次读过这篇文章,但是自Win7以来,一些文本发生了变化 - 尤其是OVERLAPPED结构中的hEvent字段, http://msdn.microsoft.com/en-us/library/ms684342(v=VS.85).aspx
等功能 GetOverlappedResult和 同步等待功能重置 自动重置事件到无信号 州。 因此,您应该使用 手动重置事件; 如果你使用的话 自动重置事件,您的应用程序可以 如果你等待,就停止响应 操作完成然后调用 使用bWait获取GetOverlappedResult 参数设置为TRUE。
你可以做一个实验吗 - 请在你的OVERLAPPED结构中分配手动重置事件而不是自动重置事件? (我没有看到你的snippit中的分配 - 不要忘记创建事件并在将结构置零后设置'hEvent')