Unix系统中,一切(磁盘文件、网络I/O、硬件设备...)都是文件,所以文件非常重要。
这篇博客讲述内核中表示一个打开文件的3种数据结构,然后简单分析了两个独立进程
同时打开一个文件的情况
一 线程文件表(process table)
进程文件表是内核表示打开文件的第一个数据结构,每个线程都有一个自动的线程文件表,
结构如下:
+------------------------+
fd 0: |fd flags | file pointer |
fd 1: |fd flags | file pointer |
... | .... |
+------------------------+
线程内每个打开的文件都对应上表的一条记录,一条记录包含两个字段
-
fd flags
文件描述符的flag,目前只有一种文件描述符flag,即FD_CLOEXE(如果FD_CLOEXE
被设置了,那么一次成功的execve
后自动关闭) -
file pointer
指向全局文件表的一条记录,全局文件表是内核表示打开文件的第二个数
据结构。
二 全局文件表(file table)
内核有一个全局文件表,它包含了系统打开的所有文件,每个文件对应全局文件表内的一条
记录,结构如下:
+--------------------------------------------------------+
|file status flag | current file offset | v-node pointer |
| ... | .... | ... |
+--------------------------------------------------------+
-
file status flag
:文件状态falg,比如read、write、append、sync等 -
current file offset
:当前读取文件的偏移量 -
v-node pointera
:指向v-node的指针,见后文
三 v-node表
+-----------------------------------------+
| v-node information | v_data |
| ... | ... |
+-----------------------------------------+
系统内每个打开的文件都对应的v-node表
的一条记录,v-node
存储的信息跟文件物理信息
有关,比如文件的类型和操作这个文件的函数。对大多数的文件来说,v-node
表中还存储了
文件的i-node
信息,i-node
信息直接从磁盘中得到,比如文件的大小,文件在磁盘上的
真正位置信息等
两个进程打开同一个文件
两个进程同时打开一个文件时:
- 每个线程都有独立的线程文件表,每个线程文件表里都有一条记录
- 全局文件表里有两条记录,分别对应两个进程的文件
- 因为两个线程打开的是同一个物理文件,全局文件表里的两条记录指向同一个
v-node
简化图形如下:
Process 1
+---+
fd 0: | | 全局文件表
fd 1: | | +---------+ v-node表
fd 2: | | | | +--------+
fd 3: | |----------->| | ---- | |
... |...| | | \ | |
+----+ | | \ | |
| | \--------->| |
| | | | |
Process 2 | | | | |
+---+ | | | | |
fd 0: | | | | | | |
fd 1: | | | | / | |
fd 2: | | | | / | |
fd 3: | | | | / +--------+
fd 4: | |----------->| |----
... |...| | |
+---+ +---------+
- 全局进程表中每个进程都独立的记录,这样每个进程可以有独立的文件状态flag和当前文
件读取位移 - 因为是同一个文件,所以共用了同一个
v-node
,当两个进程同时写入这个文件时,就会
发生写入冲突,无法预料最终的写入效果