磁盘IO

详情参见 磁盘IO:缓存IO与直接IO

缓存I/O

缓存I/O又被称作标准I/O,大多数文件系统的默认I/O操作都是缓存I/O

  • 在Linux的缓存I/O机制中,数据先从磁盘复制到内核空间的缓冲区,然后从内核空间缓冲区复制到应用程序的地址空间

  • 读操作:操作系统检查内核的缓冲区有没有需要的数据,如果已经缓存了,那么就直接从缓存中返回;否则从磁盘中读取,然后缓存在操作系统的缓存中

  • 写操作:将数据从用户空间复制到内核空间的缓存中。这时对用户程序来说写操作就已经完成,至于什么时候再写到磁盘中由操作系统决定,除非显示地调用了sync同步命令

直接IO

直接IO就是应用程序直接访问磁盘数据,而不经过内核缓冲区

文件读写

虚拟文件系统(VFS)

一个操作系统可以支持多种底层不同的文件系统(比如NTFS, FAT, ext3, ext4),为了给内核和用户进程提供统一的文件系统视图,Linux在用户进程和底层文件系统之间加入了一个抽象层,即虚拟文件系统(Virtual File System, VFS),进程所有的文件操作都通过VFS,由VFS来适配各种底层不同的文件系统,完成实际的文件操作

系统主要模块

详情参考从内核文件系统看文件读写过程

模块 说明
super_block 超级块,用于保存一个文件系统的所有元数据
dir_entry 目录项模块,管理路径的的文件和目录项
inode 指向一个具体的文件,是文件的唯一标识
open_files 打开的文件列表模块,包含所有内核已经打开的文件
file_operations 一系列文件操作函数指针的集合
address_space 记录了文件在页缓存中已经缓存了的物理页

内核数据结构

详情参考linux下多进程/多线程文件操作详解

文件节点在unix中是vnode,linux中是inode

进程文件表

每个进程都有一张进程文件表,其中的每一项都指向了某一个打开的文件

子进程会共享父进程的进程文件表

打开文件表

内核为所有打开文件维持一张文件表,其中的每一项都指向了真正的文件

打开文件表是系统级别的,和进程无关

文件节点表

文件节点表记录了文件的相关信息,包括所有者,长度,所在设备等信息

两个打开文件表项可以指向同一个文件,使得文件被进程共享

操作的原子性

  1. 创建文件的操作是原子性的
  2. read()/write()函数的调用是原子性
  3. lseek()可以设置偏移量,是原子性的

并发数据冲突

对于write()操作,我们可以通过open文件时指定O_APPEND选项来解决

多进程单线程,每个进程打开一个fd

这种情况下数据冲突的本质是存在多个fd

  • 每个fd指向不同的打开文件表项
  • 也就是拥有多个不同的文件偏移量
  • 可能会导致写入文件的数据相互覆盖

单进程多线程,单个进程打开一个fd

这种情况下线程间共用同一个fd

  • 只有一个文件表项,也就是只有一个文件偏移量
  • 如果不需要调用lseek,那么并没有数据冲突的危险

单进程多线程,每个线程打开一个fd

这种情况下线程间各自打开一个fd

  • 每个fd指向不同的打开文件表项
  • 也就是拥有多个不同的文件偏移量
  • 可能会导致写入文件的数据相互覆盖



参考

磁盘IO:缓存IO与直接IO
Linux 内核详解以及内核缓冲区技术
从内核文件系统看文件读写过程
linux下多进程/多线程文件操作详解
Linux中的文件描述符与打开文件之间的关系
Linux系统环境下关于多进程并发写同一个文件的讨论

Copyright © zhujipeng 2017 all right reserved,powered by Gitbook 该文件修订时间: 2017-11-04 14:57:24

results matching ""

    No results matching ""