POSIX 的 read() 和 write() 系统调用是原子的吗?
Posted
技术标签:
【中文标题】POSIX 的 read() 和 write() 系统调用是原子的吗?【英文标题】:Are POSIX' read() and write() system calls atomic? 【发布时间】:2013-01-03 06:40:18 【问题描述】:我正在尝试基于 Lehman 和 Yao 在 this paper 中建议的数据结构(Blink 树)和算法来实现数据库索引。在第 2 页中,作者声明:
磁盘被划分为固定大小的部分(物理页;在本文中,这些对应于树的节点)。 这些是进程唯一可以读取或写入的单元。 [强调我的] (...)
(...) 允许进程锁定和解锁磁盘页面。该锁赋予该进程对该页面的独占修改权限;此外,进程必须锁定页面才能修改该页面。 (...) 锁不会阻止其他进程读取锁定的页面。 [强调我的]
我不完全确定我的解释是否正确(我不习惯阅读学术论文),但我认为可以从强调的句子中得出结论,作者的意思是读取和写入页面的操作被假定为“原子”,从某种意义上说,如果进程 A 已经开始读取(相应地写入)页面,则另一个进程 B 可能不会开始写入(相应地读取)同一页面,直到 A 完成执行其读取(相应地)。写)操作。多个进程同时读取同一个页面当然是合法的条件,因为多个进程同时在完全不同的页面上执行任意操作(页面 P 上的进程 A,页面 Q 上的进程 B,页面 R 上的进程 C 等)也是如此。 )。
我的解释正确吗?
我可以假设 POSIX 的 read()
和 write()
系统调用在上述意义上是“原子的”吗?我是否可以依靠这些具有一些内部逻辑的系统调用来确定是否应该根据文件描述符的位置和要读取或写入的块的指定大小来临时阻止特定的 read()
或 write()
调用?
如果上述问题的答案是“否”,我应该如何推出自己的锁定机制?
【问题讨论】:
【参考方案1】:答案:
并发读取到写入可能根据操作系统、文件系统以及您打开文件时使用的标志看到撕裂的写入。下面是标志、操作系统和文件系统的简要总结。
您可以使用 POSIX 上的 fcntl() 或 Windows 上的 LockFile() 来锁定文件中的字节范围,然后再访问它们。
没有 O_DIRECT/FILE_FLAG_NO_BUFFERING:
带有 NTFS 的 Microsoft Windows 10:更新原子性 = 1 个字节
带有 ext4 的 Linux 4.2.6:更新原子性 = 1 字节
带有 ZFS 的 FreeBSD 10.2:更新原子性 = 至少 1Mb,可能是无限的 (*)
O_DIRECT/FILE_FLAG_NO_BUFFERING:
带有 NTFS 的 Microsoft Windows 10:更新原子性 = 仅当页面对齐时最多 4096 字节,否则如果 FILE_FLAG_WRITE_THROUGH 关闭,则为 512 字节,否则为 64 字节。请注意,这种原子性可能是 PCIe DMA 的一个特性,而不是 (*) 中设计的。
带有 ext4 的 Linux 4.2.6:更新原子性 = 至少 1Mb,可能是无限的 (*)。请注意,带有 ext4 的早期 Linux 肯定不会超过 4096 字节,XFS 肯定曾经有自定义锁定,但看起来最近的 Linux 终于修复了这个问题。
带有 ZFS 的 FreeBSD 10.2:更新原子性 = 至少 1Mb,可能是无限的 (*)
您可以在https://github.com/BoostGSoC13/boost.afio/blob/master/fs_probe/fs_probe_results.yaml 查看原始经验测试结果。结果是由在所有平台上使用异步文件 i/o 编写的程序生成的。请注意,我们仅在 512 字节倍数上测试撕裂偏移量,因此我不能说 512 字节扇区的部分更新是否会在读取-修改-写入周期内撕裂。
【讨论】:
【参考方案2】:我不相信你引用的文字暗示了任何类似的东西。它甚至没有提到read()
或write()
或POSIX。事实上,read()
和 write()
不能被认为是原子的。 POSIX 唯一说的是,如果写入的大小小于 PIPE_BUF
字节,write()
必须是原子的,即使这仅适用于管道。
我没有阅读您引用的论文部分的上下文,但听起来您引用的段落是在说明必须对实现进行约束,以使算法正常工作。换句话说,它表明该算法的实现需要锁定。
如何进行锁定取决于您(实施者)。如果我们正在处理一个常规文件和多个独立进程,您可以尝试fcntl(F_SETLKW)
-style 锁定。如果您的数据结构在内存中,并且您在同一个进程中处理多个线程,则其他方法可能更合适。
【讨论】:
以上是关于POSIX 的 read() 和 write() 系统调用是原子的吗?的主要内容,如果未能解决你的问题,请参考以下文章
[Linux]read/write和fread/fwrite有什么区别