在 Windows 上:是的,对于给定的HANDLE
实例,当前的异步 i/o 队列在FlushFileBuffers()
执行之前被耗尽。如果你正在编写一个数据库,你真的应该使用NtFlushBuffersFileEx()
它,它提供了更精细的同步粒度,产生了巨大的差异。
在 FreeBSD 上:当然是 ZFS,是的。我不能说我已经测试过 UFS,但如果它不一样,我会感到惊讶。在任何情况下,FreeBSD 都将缓存的异步 i/o 实现为内核线程池,只有未缓存的异步 i/o 才是真正的异步。
在 Mac OS 上:不知道,更糟糕的是,磁盘 i/o 语义在最近几个版本中无处不在。它曾经非常好,就像 BSD,但最近它已经走下坡路了。在任何情况下,异步文件 i/o 在 Mac OS 上总是几乎无法使用,最大 16 深度队列限制加上使用信号完成异步 i/o 完成的要求很难与线程代码很好地混合。
在 Linux 上:对于同步 i/o,fsync()
如果您的文件系统保证(所有流行的都这样做),yes 会强制执行每个 inode 的总排序。对于在任何情况下都只适用于 i/o 的 libaio,O_DIRECT
我相信块存储层会在告诉设备设置屏障之前刷新所有排队的 i/o,除非您禁用了屏障。对于 io_uring(你应该使用它而不是 libaio),对于非O_DIRECT
i/o,一旦 io_uring 处理了提交,文件系统对 per-inode i/o 强制执行的顺序是什么。对于带有 i/o 的 io_uring ,块存储层是一个单例,一旦 io_uring 处理了提交O_DIRECT
,就应该在整个系统中强制执行排序。
我一直提到“一旦 io_uring 处理了提交”,因为 io_uring 与环形缓冲队列一起工作。如果您将条目添加到提交队列,它将按提交顺序由 io_uring 处理(即队列被排空)。从提交的那一刻到 io_uring 消费提交的那一刻,没有排序。但是一旦 io_uring 消费了提交,目标文件系统就被告知了 i/o,并且无论它实现什么排序保证,它都将应用于它发送回 io_uring 的完成的排序。因此,当使用 io_uring 时,不要在 i/o 提交后继续操作,直到 io_uring 从提交队列中清空您的 i/o 提交请求。这自然会发生,使用系统调用告诉 io_uring 排空队列,或者对于轮询排空,您可以观看“
资料来源:我是WG21 C++ 低级 i/o 标准化参考库的作者。警告:以上所有内容纯粹来自我的记忆和经验,可能会有点烂或错误。