from : https://blog.csdn.net/luotuo44/article/details/17474099

编者云:这篇文章内容比较碎,需要有一定基础之后再看,图片给的很到位。


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

当同一个进程对同一个文件多次使用open时;

对一个文件描述符调用dup函数;

父进程使用fork创建一个子进程,子进程和上面三个表的关系;

当子进程调用exec函数,子进程和上三个表的关系又发生了什么变化;

不同的进程打开同一个文件,那么这些进程又是以怎么样的形式相关联。

本文将解释这些问题。


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

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

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

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

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


个表的作用:

  • 文件描述符表:该表记录进程打开的文件。它的表项里面有一个指针,指向存放在内核空间的文件表中的一个表项。它向用户提供一个简单的文件描述符,使得用户可以通过它方便地访问一个文件。当进程使用open打开一个文件时,内核就会在这个表中添加一个表项。如果对同一个文件打开多次,那么将有多个表项。使用dup时,也会增加一个表项。
  • 文件表:文件表保存了进程对文件读写的偏移量。该表还保存了进程对文件的存取权限。比如,进程以O\_RDONLY方式打开文件,这将记录到对应的文件表表项中。
  • 索引结点表(inode):在文件系统中,也是有一个索引结点表的。如下图所示:

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

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


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

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

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


使用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时关闭。

results matching ""

    No results matching ""