文件描述符表、文件表、索引结点表

        进程打开一个文件,会与三个表发生关联,分别是:文件描述符表、文件表、索引结点表。

        当同一个进程对同一个文件多次使用open时;对一个文件描述符调用dup函数;父进程使用fork创建一个子进程,子进程和上面三个表的关系;当子进程调用exec函数,子进程和上三个表的关系又发生了什么变化;不同的进程打开同一个文件,那么这些进程又是以怎么样的形式相关联。本文将解释这些问题。

 


文件描述符表、文件表、索引结点表存放地点:

        每个进程都有一个属于自己的文件描述符表。

        文件表存放在内核空间,由系统里的所有进程共享。

        索引结点表也存放在内核空间,由所有进程所共享。

        了解这个些表的存放位置很重要。

 


三个表的作用:

        文件描述符表:该表记录进程打开的文件。它的表项里面有一个指针,指向存放在内核空间的文件表中的一个表项。它向用户提供一个简单的文件描述符,使得用户可以通过方便地访问一个文件。

        当进程使用open打开一个文件时,内核就会在这个表中添加一个表项。如果对同一个文件打开多次,那么将有多个表项。使用dup时,也会增加一个表项。

 

        文件表:文件表保存了进程对文件读写的偏移量。该表还保存了进程对文件的存取权限。比如,进程以O_RDONLY方式打开文件,这将记录到对应的文件表表项中。

 

        索引结点表:在文件系统中,也是有一个索引结点表的。如下图所示:

         

        这两个索引结点表有千丝万缕的关系。因为内存中的索引结点表的每一个表项都是从文件系统中读入的,并且两个索引结点表有一对一的关系。所以,内存中的索引结点表的每一个表项都对应一个具体的文件。

 

        上面所说的三个表的功能,使得三个表紧密地联系在一起,文件描述符表项有一个指针指向文件表表项,文件表表项有一个指针指向索引结点表表项。



不同的进程打开同一个文件:

        不同的进程打开同一个文件,那么他们应该有各自对应的文件表表项。因为文件表表项记录了进程读写文件时的偏移量和存取权限。多个进程不可能共享一个文件偏移量。另外他们各自打开文件的权限也可能是不同的,有的是为了读、有的为了写,有的为了读写。所以,他们应该有不同的文件表表项。

此外,因为是同一个文件,所以,多个进程会共享同一个索引结点表项。即他们的文件表表项指针会指向同一个索引结点

        最终,如下图所示:

         

 


使用dup函数复制一个文件描述符:

        dup函数是用来复制一个文件描述符的。点击这个链接可以看到,复制得到的文件描述符和原描述符共享文件偏移量和一些状态。所以dup的作用仅仅是复制一个文件描述符表项,而不会复制一个文件表表项。

        于是使用dup函数后,有下图:

        

        dup函数是一个很重要的函数。平时我们在shell里面通过 >  来进行重定向,就是通过dup函数来实现的。



同一个进程多次打开同一个文件:

        每打开一次同一个文件,内核就会在文件表中增加一个表项。这是因为每次open文件时使用了不同的读写权限,而读写权限是保存在文件表表项里面的。

 

        所以,效果图如下所示:

         



父进程使用fork创建子进程:

        由于fork一个子进程,子进程将复制父进程的绝大部分东西(除了进程ID、进程的父进程ID、一些时间属性、文件锁)。所以子进程复制了父进程的整个文件描述符表。

        结果如下图所示:

        

 


进程调用exec后,文件描述符的保留情况:

        我们经常会在shell中,输入 < 进行标准输入重定向。比如$wc < test.c

        其大致的实现如下:

if(fork()==0)//child process
{
       close(0); //关闭键盘这个标准输入
       open(inputFile, O_RDONLY); //返回的文件描述符是最小的未使用的整数,此次就是0,实现了重定向
       exec(); //执行exec
}


        从上面的例子可以看到执行exec后,文件描述符是会保留的。但有时,可能一个进程有很多个文件描述符,执行exec后,都用不着了。那么此时,应该关闭它。这涉及到一个close-on-exec概念,就是在执行exec时,close(关闭)文件描述符。在默认情况下,执行exec是不关闭的。这里有一个系统调用fcntl可以关闭之。

       它的原型为:

int fcntl(int fd,int cmd, … /* int arg */);

        第一个参数是文件描述符,第二个参数用来指定是要进行的操作。第三个参数依赖于第二个参数

 

       与本文相关的是操作是 F_GETFD和F_SETFD。其分别用来获取close-on-exec,设置close-on-exec标识的值。

       可以通过

fcntl(fd, F_SETFD, 1);

      来关闭文件描述符。

       即参数arg为0时,不关闭;为1时关闭。

       关于fcntl函数的详细使用,可以参考http://www.linuxmanpages.com/man2/fcntl.2.php


       参考:《UNIX环境高级编程》、《UNIX操作系统设计》

 

  • 18
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
设计时间:2011-1-5至2011-1-7 专业年级:08计科4班: 一.设计目的: 通过操作系统其中一个子系统的设计和实现,掌握Linux文件系统的基本原理、结构 和实现方法,掌握Linux文件系统中文件的建立、打开、读/写、执行、属性等系统调用 的使用,学会设计简单的文件系统并实现一组操作,以与学习文件系统的系统调用命令 ,提高对文件系统实现功能的理解和掌握。同时,掌握操作系统设计的方法与技巧,增 强系统软件设计的实际工作能力。 二.设计容: 为LINUX 设计一个简单的二级文件系统。本文件系统采用类似DOS系统的文件管理方式,每次调用 该文件系统时,首先申请一定的存空间,然后对该存空间进行分配。将申请到的空间划 分为目录区,文件区;采用位示图进行空间管理,盘块的分配使用显示(FAT)的方式 。每次调用该文件系统时自动为其分配空间,并将上次操作的结果从硬盘上调入存;当 结束调用时则将操作的结果重新存入硬盘,以便下次调用。(每次使用都会自动搜索文 件系统,以此确定是否是第一次使用;若是则格式化生成文件系统,否则读取已存在的 文件系统。) 三.设计过程 1. 实现功能 该系统具备下列功能: login 用户登录 logout 注销 mkdir/md 创建目录rmdir/rd 删除目录 cd/cd .. 修改目录creat 创建文件 open 打开文件dir 显示当前目录和文件 write 读文件 delete 删除文件 close 关闭文件 2. 添加功能 1. 制作了一个"操作命令符"列框,说明接下来如何操作,这样有利于更好地阅读、操 作和运行程序,使不懂得程序代码的人也可以运行该程序,更好地理解该程序实现 的功能。 2. 在命令解释层函数cmdexp()里加了一些选择和操作功能,增加程序实现的功能,如原 来程序只有显示当前目录和文件、创建目录和修改目录的功能,把它拓展到系统所 要求的全部功能,并在原有的程序的基础上进行相应的修改,使程序更加完善。 3. 设计思路 (1) 要将文件存储在磁盘上,必须为之分配相应的存储空间,并对文件存储空间进行管理, 为了简化对文件的访问和共享,还应设置相应的用户文件描述文件文件卷的组织 UNIX中,把每个磁盘(带)看作是一个文件卷,每个文件卷上可存放一个具有独立目 录结构的文件系统。一个文件卷包含许多物理块,并按块号排列如下图: "0# 1# 2# 3# ……K# K+1# ……N# " 其中,0#块用于系统引导或空闲,1#为超级块(superblock),存放文件卷的资源管理 信息,如整个文件卷的盘块数、磁盘索引结点的盘块数、空闲盘块号栈与指针等。2#~K #存放磁盘索引结点。每个索引结点64B,第K+1#~N#存放文件数据。 空闲盘块的组织 UNIX采用成组法组织空闲盘块。它将若干个空闲盘块划归一个组,将每组中所有盘块号 存放在其前一组的第一个空闲盘块中,而第一组中所有空闲盘块号放入超级块的空闲盘 块号栈中。 例: 超级块 "109 "106 "103 "100 "95 " " "211 "208 "205 "202 " " "310 "307 "304 "301 " " 空闲盘块的分配与回收 核要从文件系统中分配一盘块时,先检查超级块空闲盘块号栈是否已上锁。是则调用 sleep睡眠,否则将超级块中空闲盘块栈栈顶盘块号分配出去。 回收时,若空闲盘块号栈未满,直接将回收盘块编号记入空闲盘块号栈中。若回收时 栈已满,须先将栈中的所有空闲盘块号复制到新回收的盘块中,再将新回收盘块的编号 作为新栈的栈底块号进栈。 (2) UNIX中,为了加速对文件目录的查找,将文件名和文件说明分开,由文件说明形成一个 称为索引结点的数据结构,而相应的文件目录项则只由文件符号名和指向索引结点的指 针构成。对目录的管理应包括的功能有: 对索引结点的管理:每个文件都有一唯一的磁盘索引结点(di_node)。文件被打开后 ,还有一个存索引结点(i_node)。创建一新文件时,就为之建立一个磁盘索引结点,以 将文件的有关信息记入其中,并将用户提供的文件名和磁盘索引结点号一并组成一个新 目录项,记入其父目录文件中。文件被撤消时,系统要回收该文件的磁盘索引结点,从 其父目录中删除该目录项。随着文件的打开与关闭,系统还要为之分配和回收存索引结 点。 磁盘索引结点中,包含有关文件的下述一系列信息:文件模式di_mode、文件所有者 用户标识符di_uid、同组用户标识符di_gid、文件长度di_size、文件的联接计数di_nl ink、文件的物理地址di_addr、文件的访问时间di_atime、文件的修改时间di_mtime和 文件的建立时间di_citime。 存索引结点文件被打开后,系统为它在存索引

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值