POSIX的read()和write()系统调用是原子的吗?

时间:2013-01-19 19:06:26

标签: concurrency posix b-tree database-indexes

我正在尝试基于数据结构(B link 树)和Lehman和Yao在this paper中建议的算法来实现数据库索引。在第2页中,作者声明:

  

磁盘分区为固定大小的部分(物理页面;在本文中,这些对应于树的节点)。 这些是唯一可以通过流程读取或写入的单位。 [强调我的](...)

     

(...)允许进程锁定和解锁磁盘页面。此锁为该进程提供该页面的独占修改权限;此外,进程必须锁定页面才能修改该页面。 (...)锁定阻止其他进程读取锁定的页面。 [强调我的]

我不完全确定我的解释是否正确(我不习惯阅读学术论文),但我认为可以从强调的句子中得出结论,作者的意思是读取和写入页面的操作被认为是“原子”,在某种意义上说,如果进程A已经开始读取(分别写入)一个页面,另一个进程B可能不会开始写入(分别读取)该页面,直到A完成执行其读取(resp。写)操作。当然,同时读取同一页面的多个进程是合法的条件,因为多个进程同时在不同的页面上执行任意操作(页面P上的进程A,页面Q上的进程B,页面R上的进程C等)。 )。

  1. 我的解释是否正确?

  2. 我可以假设POSIX'read()write()系统调用在上述意义上是“原子的”吗?我是否可以依赖这些具有一些内部逻辑的系统调用来确定是否应根据文件描述符的位置和要读取的块的指定大小来临时阻止特定的read()write()调用还是写的?

  3. 如果上述问题的答案为“否”,我应该如何推出自己的锁定机制?

2 个答案:

答案 0 :(得分:3)

我不相信你引用的文字暗示任何类似的东西。它甚至没有提到read()write()或POSIX。实际上,read()write()不能依赖于原子。 POSIX唯一说的是,如果写入的大小小于write()字节,PIPE_BUF必须是原子的,甚至只适用于管道。

我没有阅读您引用的论文部分的上下文,但听起来您引用的段落是说明必须在实现上施加约束才能使算法正常工作。换句话说,它声明该算法的实现需要锁定。

如何进行锁定取决于您(实施者)。如果我们正在处理常规文件和多个独立进程,您可以尝试fcntl(F_SETLKW) - 样式锁定。如果您的数据结构在内存中,并且您在同一个进程中处理多个线程,那么其他一些可能是合适的。

答案 1 :(得分:2)

数目:

  1. 对写入的并发读取可能根据操作系统,文件系统以及打开文件的标记看到撕裂的写入。标志,操作系统和归档系统的快速摘要如下。

  2. 在Windows上使用POSIX或LockFile()上的fcntl()访问文件之前,可以锁定文件中的字节范围。

  3. 否O_DIRECT / FILE_FLAG_NO_BUFFERING:

    带有NTFS的Microsoft Windows 10:update atomicity = 1 byte

    Linux 4.2.6 with ext4:update atomicity = 1 byte

    带有ZFS的FreeBSD 10.2:update atomicity =至少1Mb,可能是无限(*)

    O_DIRECT / FILE_FLAG_NO_BUFFERING:

    带有NTFS的Microsoft Windows 10:仅在页面对齐时更新原子性=最多4096字节,否则如果FILE_FLAG_WRITE_THROUGH关闭则为512字节,否则为64字节。请注意,这种原子性可能是PCIe DMA的一个特性,而不是(*)中设计的。

    Linux 4.2.6 with ext4:update atomicity =至少1Mb,可能是无限(*)。请注意,早期使用ext4的Linux肯定没有超过4096字节,XFS肯定用于自定义锁定,但看起来最近Linux已经解决了这个问题。

    带有ZFS的FreeBSD 10.2:update atomicity =至少1Mb,可能是无限(*)

    您可以在https://github.com/BoostGSoC13/boost.afio/blob/master/fs_probe/fs_probe_results.yaml查看原始经验测试结果。结果是由在所有平台上使用异步文件i / o编写的程序生成的。注意我们只测试512字节倍数的撕裂偏移,所以我不能说在读 - 修改 - 写周期中是否会撕裂512字节扇区的部分更新。