Linux文件共享(一)——进程与打开文件

时间:2022-03-25 15:04:41

Linux支持在不同进程间共享打开文件。为了说明文件共享,先来说明内核用于所有I/O的数据结构。 他们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。

0.1和文件有关的对象

(1) inodei节点): 保存一个文件的通用信息,每个inode有一个inode number,在文件系统中,一个inode number能够唯一地标识一个文件。

(2) dentry(目录项对象):每个dentry代表路径中的一个特定部分。保存一个目录的链接信息。个人理解:描述一个文件和一个名字的对应关系。

(3) file(文件对象):保存一个打开的文件与一个进程的关系,文件对象表示进程已经打开的文件 在内存中的表示,该对象不是物理上的文件。它是由相应的open()系统调用创建,由close()系统调用销毁(只有其引用计数为0时才销毁)。多个进程可以打开和操作同一个文件,所以同一个文件也可能存在多个对应的文件对象。 它即为apue中所说的“目录表项”,内涵文件偏移等信息。

0.2和进程有关的对象

(1)  files_struct每个进程用一个files_struct结构来记录文件描述符的使用情况,这个结构称为用户打开文件表(含有描述符表)。它是进程的私有数据。它即为apue中的“打开文件描述符表”。

(2) fs_structfs_struct 结构描述进程与文件系统的关系。

这些对象的关系如下图所示。

 Linux文件共享(一)——进程与打开文件

0.3 Apue文件对象解读

再来看一下apue中描述的关于文件和进程的关系,如下图( 3-1显示了进程的三张表之间的关系。该进程有两个不同的打开文件一个文件打开为标准输入(文件表述符0),另一个打开为标准输出(文件描述符1)

 Linux文件共享(一)——进程与打开文件

1)每个进程在进程表中都有一个记录项(打开文件描述符表),记录项中包含有一张打开文件的描述符表,可将其视为一个矢量,每个描述符占用一项。

   每个文件描述符相关连的是:

·       文件描述符标志close_on_exec)。

·       指向一个文件表项的指针。

注解:这里描述的即为Linux进程描述符(tast_struct)中的filesfiles_struct类型)。

2)内核为所有打开文件维持一张文件表。每个文件表项包含:

·        文件状态标志(包含读写,填写,同步,非阻塞等)

·        当前文件偏移量

·        指向该文件v节点表项的指针。

注解:这里描述的“文件表项”即为linux系统下的文件对象(file)。

3)每个打开的文件都有一个v节点结构。v节点包含了文件类型和对此文件进行各种操作的函数的指针。对于大多数文件,v节点还包括了该文件的i节点。这些信息是再打开文件时从磁盘上读入内存的。这些文件都是从磁盘读入内存的,所以可以快速使用这些参数。

注解:这里描述的v节点,在linux中即为i节点,对应inode对象。

之后我们的讨论也主要围绕这三大对象。      

0.4 引用计数

在我们讨论的几个和文件有关的对象中都存在引用计数,而他们的含义各不相同,理解这些引用计数对我们下面的讨论至关重要。

(1) file_struct引用计数:表明共享此结构的进程(线程)数。(我们讨论线程共享文件会用到)

(2) fs_struct引用计数:表明共享此结构的进程(线程)数。(我们讨论线程共享文件会用到)

(3) file对象引用计数:打开文件引用计数,引用这个file对象描述符数。(dupfork都会增加这个计数,第一次open会使此计数为1close会减小此计数,为0时销毁file对象)

(4) dentry引用计数:每一个计数对应一个file对象。

(5) inode引用计数:每一个计数对应一个dentry

扩展:

1close_on_exec标志

从图中可见,这个标着在进程的files_struct中, 是一个进程所有文件描述符(文件句柄)的位图标志,每个比特位对应一个打开的文件描述符,用于确定在调用系统调用execve()时需要关闭的文件描述符,可用fcntl设置。

2附录:i节点结构

struct dinode
{
 ushort di_mode;  /*文件类型+用户权限*/
 short di_nlink;  /*文件链接数*/
 ushort di_uid;  /*属主用户id*/
 ushort di_gid;  /*属主用户组id*/
 off_t di_size;  /*文件大小*/
 char di_addr[40]; /*文件数据区起点地址*/
 time_t di_atime; /*最后访问时间*/
 time_t di_mtime; /*最后修改时间*/
 time_t di_ctime; /*创建时间*/
};