【问题标题】:ReadFile doesn't work asynchronously on Win7 and Win2k8ReadFile 在 Win7 和 Win2k8 上不能异步工作
【发布时间】:2011-02-02 19:22:58
【问题描述】:

根据 MSDN,ReadFile 可以通过 2 种不同的方式读取数据:同步和异步。 我需要第二个。以下代码演示了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没有阻塞并在同一秒立即返回,而读取过程持续了3秒。这是正常的异步读取。

但在 Windows 7 和 Windows 2008 上,我得到以下结果: 阅读:1296661205 发送:1296661209 完成:1296661209。 这是一种同步读取的行为。

MSDN 说 async ReadFile 有时可以表现为同步(例如,当文件被压缩或加密时)。但是这种情况下的返回值应该是TRUE和GetLastError() == NO_ERROR。 在 Windows 7 上,我得到 FALSE 和 GetLastError() == ERROR_IO_PENDING。所以 WinApi 告诉我这是一个异步调用,但是当我查看测试时发现它不是!

我不是唯一发现此“错误”的人:请阅读 ReadFile MSDN 页面上的评论。

那么解决办法是什么?有人知道吗?丹尼斯发现这种奇怪的行为已经过去了 14 个月。

【问题讨论】:

  • Win7 的文件 I/O 子系统发生了巨大变化。否则这不是问题,当您遵守合同时,您会得到正确的阅读。
  • 在哪里可以阅读文档?我做错了什么?
  • 去年,我正在调查执行异步 WriteFile 调用并遇到与您相同的问题。 WriteFile 调用将阻塞并返回 PENDING。后续等待 IO 结果也将立即返回。唯一的解决方案是 CreateThread 或 QueueUserWorkItem。 (或者忍受主线程上的性能命中)。我按照下面的建议使用了 BUFFERING 标志。没有骰子。
  • 我也试图找到解决这个问题的方法。最终也使用了一个线程。

标签: winapi windows-7 asynchronous


【解决方案1】:

我不知道“c:\1.avi”文件的大小,但您提供给 Windows 的缓冲区大小(256M!)可能足以容纳该文件。所以windows决定读取整个文件并以它喜欢的方式将其放入缓冲区。你不会对 Windows 说“我想要异步”,而是说“我知道如何处理异步”。

只需将缓冲区大小更改为 1024,您的程序的行为将完全相同,但仅读取 1024 个字节(并返回 ERROR_IO_PENDING)。

通常,您执行异步操作是因为您想在操作期间执行其他操作。查看此处的示例:Testing for the End of a File,因为它演示了异步 ReadFile。如果您更改样本的缓冲区并将其设置为较大的值,它的行为应该与您的完全相同。

PS:我建议你不要依赖时间样本来检查事情,使用返回码和事件

【讨论】:

  • 1.avi 的大小为 600 MB。 Windows 只读取文件的一部分。从磁盘读取 256 MB 需要几秒钟。我认为异步 ReadFile 应该花费不到 1 秒的时间。但是时间表明 ReadFile 在暂停我的线程时会阻塞并读取 256 MB!
  • 我想从 ReadFile 中读取的只是读取这 256 mb 的空间,而不会暂停我的线程这么久!
  • @f0b0s - 再说一次,异步 ReadFile 并不意味着“亲爱的 Windows,请现在返回并稍后做你的工作”,它只是意味着“我可以处理异步 IO 操作”。没有每次调用之间花费的最大时间或读取的最大字节数的概念,当然除了您传递的缓冲区的大小。如果你只关心读取 256M 并且不被阻塞,你可以使用另一个线程(如线程池的 QueueUserWorkItem 函数)来完成。
  • 如果是这样,那就太糟糕了。在 linux 中异步意味着 - 不要阻塞,请在 OS 线程中读取。我同意你的观点,这不是 Windows 的错误,而是一种奇怪的行为。但是你应该理解我的立场:我需要非阻塞的 ReadFile 不是因为我可以处理它,而是我需要这种行为来让我的数据库快速工作。
  • 您可以使用ReadFileEx 进行强制异步
【解决方案2】:

根据this,我怀疑在您的情况下它应该返回 TRUE。但也可能是Win7/Win2k8上完成模式默认设置不同。 尝试使用SetFileCompletionNotificationModes() 设置不同的模式。

【讨论】:

  • 不,它返回 false!我仔细检查了。但我会尝试更改设置,谢谢!
【解决方案3】:

您是否尝试过按照@Simon Mourier 的建议使用事件?我知道文档说该事件不是必需的,但是如果您在@Simon Mourier 提供的链接中看到示例,它正在使用事件进行异步读取。

【讨论】:

  • 是的,我做到了。该代码只是为了展示我的问题的想法。 ReadFile 返回 ERROR_IO_PENDING,WaitForSingleObject 立即返回。
【解决方案4】:

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 和 同步等待功能重置 自动复位事件到无信号 状态。 因此,您应该使用 手动重置事件如果你使用 自动重置事件,您的应用程序可以 如果您等待,请停止响应 操作完成然后调用 GetOverlappedResult 与 bWait 参数设置为 TRUE。

您能做一个实验吗?请在您的 OVERLAPPED 结构中分配手动重置事件而不是自动重置事件? (我没有在您的代码片段中看到分配 - 不要忘记在将结构归零后创建事件并设置“hEvent”)

【讨论】:

  • 我目前正在阅读 Richter 的书,而我的基于 OVERLAPPED 的课程使用手动重置事件(只是因为我只需要一次此事件:操作完成时)。每个新的异步过度都会获得带有新事件的新 OVERLAPPED 结构。
  • 我尝试了手动事件和 GetOverlappedResult -- 不,写入是异步的,读取是同步的
【解决方案5】:

这可能与缓存有关。尝试打开非缓存文件(FILE_FLAG_NO_BUFFERING)

编辑

这实际上记录在 ReadFile 的 MSDN 文档中:

注意如果打开了文件或设备 对于异步 I/O,后续调用 使用 ReadFile 等函数 该句柄通常返回 立即,但也可以表现 相对于阻塞同步 执行。有关更多信息,请参阅 http://support.microsoft.com/kb/156932.

【讨论】:

  • 读取非缓存文件的所有对齐规则确实​​令人不快
猜你喜欢
  • 2011-03-09
  • 2013-03-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-31
  • 2017-12-28
  • 2021-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多