linux 多进程间文件共享机制

一、原理

linux 支持多进程间共享打开文件,即同一时刻允许多个进程同时打开同个文件,每个进程之间的读写操作互不影响。

为了实现这一个机制,linux 内核使用了三种数据结构来表示打开的文件,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。

1.1 内核数据结构

每个进程的进程表中有一个记录项,包含了当前进程所有打开的文件描述符,它包含了一个指向文件表项的指针和文件描述符标志。

内核中,为所有打开的文件维持一张表,它包含了以下内容:

  • 当前文件打开的状态:以何种方式打开的该文件,只读、只写或是可读可写等。
  • 当前文件的偏移量:当前文件指针所处的位置。
  • 指向该文件节点表的指针:节点包含了当前文件的属性信息。

每个文件的信息被封装在一个 v 节点表项中,包含了当前文件的文件名、所有者以及 inode 等信息。

三者之间的状态关系为:

1.2 多进程共享同一个文件

对于多个进程打开的同一个文件,其状态关系为:

正因为每个文件描述符都有一个属于自己的文件表项,所以每个进程间的文件指针偏移相互独立,互相读写不干扰:

  • 每次完成 write 后,文件表项的当前文件指针偏移量也会立马加上写入的字节数。
  • 如果打开文件的时候加了 O_APPEND 参数,每次写入数据前会先把偏移量设置到文件末尾。
  • 通过 lseek 函数只修改当前文件偏移量,不进行任何 I/O 操作。

有一个要注意的是,每次 fork 进程后,子进程会复制父进程的文件描述符,两者相互独立。

二、 dup 和 dup2

dup 和 dup2 都可以用来复制一个现有的文件描述符,其用法如下:

dup 函数直接把复制后的文件描述符返回,返回的一定是当前文件描述符表中的最小数值。

对于 dup2,可以通过 fd2 表示新描述符的值,如果 fd2 已经打开,系统会先关闭。如果 fd1 等于 fd2,则直接返回不关闭。

复制过后的文件描述符共享一个文件表项,共享后的状态如下:

我们可以通过一个程序来验证这一个结论:

上面的代码中通过 fd_1 打开文件 data.txtfd_2 复制 fd_1,两个文件描述符文件从文件中读取 5 个字节数据并打印出来。

编译代码执行:

可以看到,fd_2 读取的数据是从第 5 个字节开始,即从 fd_1 读完偏移处开始,两者确实共享了同一个文件表项。

发表评论