11 Apr 2022
FD的全称是 file descriptor 文件描述符。在介绍FD之前,我们先来了解几个问题。
在文件系统中,如果我和你都被允许访问一个文件,我们可以共享文件的数据吗?
答案是:yes。
如果两个进程在同一个文件上读取和写入,它们使用的是同样的文件偏移量吗?
答案是:no。
如果一个进程把同一个文件打开两次,它应该有一个fd还是有两个?在这种情况下,这两个打开共享同一个文件偏移量吗?
答案是:two,no,它们各自拥有自己的文件偏移量。
如果两个线程使用了同一个fd,它们用的是同一个文件偏移量吗?
答案是:yes。
如果一个父进程创造了一个子进程,子进程会继承父进程的fd吗?它们会不会使用同样的文件偏移量?
答案是:yes,yes
先来说明几个事实:
在明确了以上事实后,问题是,我们需要什么样的数据结构(任何人都不会天真的认为仅靠一个小小的整数就可以代表一个fd,它背后肯定是链接着一个文件打开的详细信息)来管理fd?
进程独享)每一个进程,拥有一个单独的fd表。举个例子,当一个进程调用open系统调用打开一个文件时,open返回了3这个数字,代表了fd表中的第4个位置(0,1,2,3)。这个fd表同时包含了指向其他数据结构的指针。
答案:不可以,因为在*nix系统中,创建进程的方式,是完整的拷贝一个进程的信息成为一个新的进程。如果文件偏移量存在进程的fd表里面,那么意味着新的进程会拥有一个单独的文件偏移量信息,当父进程的文件偏移量变动时,子进程感知不到,因为父子进程是各自独立的fd表。此时,如果我们希望在父子进程中共享文件打开信息时,由于父子进程各自独立的fd表,则无法实现这个目的。所以,更明智的做法是,将文件偏移量储存在另外一个地方,而父子进程的fd表同时来引用同一个文件偏移量,来达到文件信息共享的目的。
首先,每一个文件偏移量对应着一个open系统调用。所以,我们需要一个数据结构来储存每次open系统调用的结果。它就是文件打开表(file table OR open file table)(所有进程共享)。
文件打开表中储存了如下信息:
实际文件对象,我们称之为Vnode(virtual node),是文件在内存中的展现形式。而许许多多的实际文件对象,储存在一个Vnode table(所有进程共享)中。
Vnode table中储存了如下信息:
