4

当我运行这个程序

OVERLAPPED o;

int main()
{
    ..
    CreateIoCompletionPort(....);

    for (int i = 0; i<10; i++)
    {
        WriteFile(..,&o);

        OVERLAPPED* po;
        GetQueuedCompletionStatus(..,&po);
    }
}

似乎 WriteFile 直到写入工作完成才返回。同时,调用 GetQueuedCompletionStatus()。该行为类似于同步 IO 操作,而不是异步 IO 操作。

这是为什么?

4

4 回答 4

2

如果文件句柄和卷启用了写入缓存,则文件操作可能只需要一个内存副本缓存即可完成,稍后会延迟刷新。由于没有发生实际的 IO,因此在这种情况下没有理由进行异步 IO。

在内部,每个 IO 操作都由一个IRP(IO 请求包)表示。它由内核创建并交给文件系统来处理请求,它通过分层驱动程序向下传递,直到请求成为实际的磁盘控制器命令。该驱动程序将发出请求,将 IRP 标记为待处理并返回对线程的控制。如果为重叠 IO 打开句柄,内核会立即将控制权交还给您的程序。否则,内核将等待 IRP 完成后再返回。

然而,并不是所有的 IO 操作都能一直到磁盘。文件系统可以确定写入应该被缓存,直到稍后才写入。甚至还有一个可以完全使用缓存来满足操作的特殊路径,称为快速 IO。即使您发出异步请求,快速 IO 也始终是同步的,因为它只是将数据复制到缓存中和从缓存中复制出来。

进程监视器,在高级输出模式下,显示不同的模式,并在 IRP 未决时在状态字段中显示空白。

写入缓存中允许未完成的数据量是有限制的。一旦填满,写入操作不会立即完成。尝试一次写入大量数据,并进行可能的操作。

于 2009-05-06T18:09:06.130 回答
1

我写了一篇博客,题为“什么时候异步文件写入不是异步的”,不幸的是,答案是“大部分时间”。请参阅此处的帖子:http: //www.lenholgate.com/blog/2008/02/when-are-asynchronous-file-writes-not-asynchronous.html

它的要点是:

  • 出于安全原因,Windows 以同步方式扩展文件
  • 您可以尝试通过在开始之前将文件的结尾设置为较大的值,然后在完成时将文件修剪为正确的大小来解决此问题。
  • 您可以通过使用告诉缓存管理器使用您的缓冲区而不是它的缓冲区 FILE_FLAG_NO_BUFFERING
  • 至少它不像你被迫使用那样糟糕FILE_FLAG_WRITE_THROUGH
于 2009-05-07T06:58:23.490 回答
0

如果 GetQueuedCompletionStatus 正在被调用,那么对 WriteFile 的调用是同步的(并且它已经返回),但是如果它是异步的,即使在返回之后它仍然可以修改 &o。

于 2009-05-06T17:25:06.923 回答
0

从MSDN的这个页面:

对于异步写入操作,hFile 可以是使用 FILE_FLAG_OVERLAPPED标志的 CreateFile 函数打开的任何句柄,也可以是套接字或接受函数返回的套接字句柄。

另外,从这个页面

如果提供了句柄,则必须为重叠 I/O 完成打开它。例如,您必须FILE_FLAG_OVERLAPPED在使用 CreateFile 函数获取句柄时指定标志。

于 2009-05-06T17:28:06.743 回答