【问题标题】:How to open a file in windows asynchronously如何在windows中异步打开文件
【发布时间】:2017-05-09 03:01:00
【问题描述】:

有没有办法在 Windows 中异步打开文件? CreateFile API 函数只有 FILE_FLAG_OVERLAPPED 允许进一步的异步读写。尽管如此,文件的打开似乎是同步的。鉴于它必须访问文件系统(并可能执行昂贵的 IO 操作),它可能是一个潜在的阻塞器。

这实际上是一个潜在的问题,是否可以在 .NET 中异步打开文件(因为不能等待 FileStream ctor)。但是如果在操作系统中没有办法做到这一点,那么这个问题就毫无意义了。

【问题讨论】:

  • 如果有异步调用的方法,你会如何建议CreateFile 报告错误(甚至传回有效句柄)?你问题的第二部分没有任何意义。当然,您始终可以在调用之上实现异步框架调用,这本身并不是异步的。例如,UWP 仅提供异步调用来打开文件,即使它执行严格同步的 API 调用。
  • @IInspectable - 与 Windows 中任何其他重叠操作的工作方式相同。 IE。在重叠结构中,您将传递一个回调函数,该函数将返回一个句柄或错误代码。与此类似:msdn.microsoft.com/en-us/library/windows/desktop/aa364052.aspx Re 第二部分,这有点跑题了。当然,最好有“假”异步 api,它在后台使用线程。尽管如此,除非整个链以这种方式工作,否则它会阻碍异步流的好处。只是我的意见...
  • “尽管如此,除非整个链以这种方式工作,否则它会阻碍异步流的优势。” - 那么,继续,放弃 .NET 并转向 UWP, 一切都是这样工作的。或者使用Parallel Patterns Library,这样您就可以将任何同步调用包装到异步接口中。或 C++'std::async 就此事。归根结底,必须有人启动一个线程,或者使用现有的线程池线程来实现异步。
  • @Elephantik - “与 Windows 中任何其他重叠操作的工作方式相同” - 用于创建/打开文件 (CreateFile -> ZwOpenFile, ZwCreateFile -> IoCreateFile -> ObOpenObjectByName) 的任何 api 都不接受参数 apc 回调函数或事件。并且因为尚未创建句柄 - 没有绑定到某些 IOCP - 所以没有办法,即使使用低级 api,即使来自内核模式。
  • @IInspectable: At the end of the day, someone will have to spin up a thread, or use an existing thread pool thread to implement asynchronicity. 不。异步不依赖于线程。

标签: .net windows file winapi asynchronous


【解决方案1】:

不幸的是,在用户模式下无法异步创建/打开文件。即使驱动程序为IRP_MJ_CREATE 返回STATUS_PENDING,在这种情况下,系统将等待驱动程序完成IRP,然后再从创建/打开文件函数之一返回控制权。

只有在内核模式下才有可能,如果您自己格式化IRP_MJ_CREATE 并将其发送给驱动程序。但即使在这种情况下,驱动程序也几乎总是会同步处理IRP_MJ_CREATE


API 是异步的 - 必须以某种方式在操作完成时通知调用者

windows为此使用了3种方式

  1. 参数中的一些回调例程,通常是 APC (PIO_APC_ROUTINE) 操作完成时调用
  2. 参数中的一些事件,当操作完成时,事件设置在 信号状态。
  3. api 调用中使用的文件句柄为某些 IOCP 绑定。什么时候 操作完成的数据包排队到 IOCP。 (我们稍后通过调用 GetQueuedCompletionStatus (ZwRemoveIoCompletion) 或 KeRemoveQueue 删除此数据包

3) 在我们的例子中是不可能的,因为尚未创建文件句柄,所以它不能绑定到任何 IOCP。关于 1) 和 2) 让我们查找文件打开/创建 api 签名:

在用户模式下,用于打开/创建文件的最低级别 api 是 ZwOpenFileZwCreateFileCreateFileZwCreateFile 的外壳。在内核模式NtOpenFile -> NtCreateFile -> IoCreateFile -> IoCreateFileEx 甚至 - IoCreateFileEx(用于创建文件的最低级别 api) - 没有事件或 [Apc] 回调参数 - 所以不是异步的. IoCreateFileEx 调用 ObOpenObjectByName(未记录,但导出的例程) - 这里也没有 1)或 2)参数 - 这也是设计 api 同步的

【讨论】:

    【解决方案2】:

    有没有办法在 Windows 中异步打开文件?

    不,很遗憾。有趣的是,在设备驱动程序级别,所有此类交互都是异步的(或者可以至少是异步的)。但这并没有在 Win32 级别公开。

    UWP 异步文件打开 API 只是伪异步 API - 它们将同步工作委托给线程池。它们并不是真正的异步。如果您希望在 .NET 上以非阻塞方式打开文件(如果您通过网络共享处理文件,这通常是可取的),您需要做同样的事情。

    【讨论】:

    • “在设备驱动程序级别,所有此类交互都是异步的(或者至少可以是异步的)。” - 仅当直接发送 IRP_MJ_CREATE - 可以是异步的。甚至IoCreateFileObOpenObjectByName - 同步api
    【解决方案3】:

    不幸的是,CreateFile 机制将创建句柄的概念与将其与磁盘上某处的命名文件相关联的概念混为一谈。

    而对于套接字,您调用一个函数来创建一个套接字句柄,然后将它与一个端点(实际上是一个名称)关联(绑定)。

    MS 可以对文件执行类似的操作,您可以先分配未绑定的句柄,然后将其与完成端口关联,然后异步请求与文件路径关联,然后在完成时发出信号。

    因为面对现实,所有网络重定向器的底层都是异步的,IO 管理器对 IRP 的所有管理也是如此。

    30 年后,在 Windows 中仍然无法做到这一点,这太疯狂了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-27
      • 2023-01-26
      • 1970-01-01
      • 2013-02-10
      • 2021-09-22
      • 2016-09-22
      • 2013-07-11
      • 1970-01-01
      相关资源
      最近更新 更多