进程打开文件会涉及三个表:进程的文件描述符表、系统的打开文件表、系统的inode

1. 文件描述符表(FD 表)

  • 作用: 每个进程独有,用于追踪进程当前打开的文件。
  • 内容: 是一个数组,存放文件描述符(整数)与打开文件表项的指针的映射。
  • 代表性内容:
    fd 0 -> stdin
    fd 1 -> stdout
    fd 3 -> pointer to file table entry X

2. 系统打开文件表(file table)

  • 作用: 系统级别,用于管理所有进程当前打开的文件。
  • 内容: 每个表项对应一个打开文件,包含:
  • 读写指针
  • 打开模式(只读/读写等)。open(“file”, “rw”)时指定的读写模式就保存在这里。
  • 指向 inode 表的指针
  • 引用计数
  • 代表性内容:
    offset: 1024
    flags: O_RDWR
    inode ptr: → inode#123

3. inode 表(inode table)

  • 作用: 表示磁盘上实际的文件元信息,多个文件描述符可能共用。打开一个文件主要操作就在这里,将目标文件的inode节点复制到这里来。
  • 内容: 文件的元数据:
  • 文件类型、权限
  • 文件大小
  • 磁盘块位置
  • 引用计数(在内存中时,包括了打开文件表的引用+磁盘中硬链接的引用)
  • 代表性内容:
    inode#123: size=8KB, owner=UID1000, blocks=[...], type=regular file

而影响这三个表,最具代表性的就是openforkdup

open():首先,操作系统允许一个进程多次使用open打开同一个文件,并且每一次open都一定会在进程文件描述符表和系统的文件打开表创建一个表项。由于文件的读写指针存储在的文件打开表中,因此同一个进程不同的open同一个文件以及不同进程open同一个文件都意味着返回的fd指向各自不同的打开文件表的表项,并且不影响对方的读写指针。两个打开文件表的表项指向同一个inode表。

open()函数虽然说不会重复打开文件,但这指的是不会重复调度同一个inode节点到内存中的inode表中。

open()函数只要到一个文件路径就会按照这个文件路径去检索,检索到inode节点后会带着这个节点的id去系统的inode表中对比看看是不是已经加载过了。如果能找到就不用再多启动一次磁盘,让新创建的文件打开表的表项指向这个inode即可。因此这就会出现,两个打开文件表的表项指向同一个inode表表项的情况。当然,如果是硬链接,即使open的文件路径不同也可能出现这一情况。

dup()dup的作用就是复制文件描述符表项,返回不同的fd,这意味着一个进程会有两个文件描述符表项指向同一个打开文件表的表项。当然,这也使得两个fd共享同一个读写指针。

fork():因为父子进程的关系,所以即使是两个进程也会出现各自的文件描述符表项指向同一个打开文件表的表项。因此这两个文件的读写肯定会影响到对方。