linux文件I/O之文件共享

1.    3种数据结构

     在了解文件共享之前先熟悉3个数据结构:进程表项, 文件表项,v节点表项,它们用来表示一个打开的文件。

    (1)进程表项:每个进程在进程表中有一个记录项, 记录项包含一张打开文件描述符表,文件描述符包含:

               a.    文件描述符标志(close_on_exec)

               b.    指向一个文件表项的指针

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

               a.    文件状态标志(如O_RDONLY, O_RDWR, O_APPEND等)

               b.    文件当前偏移量

               c.    指向该文件v节点的指针

      (3)v节点表项:每个打开的文件有一个v节点表项,包含:

                a.    文件类型

                b.    对该文件进行操作的各个函数的指针

                c.    i-node(包含文件长度、文件所有者、指向文件实际数据块在磁盘上所在位置的指针等信息)

        这3种数据结构的相互关系如图所示:

            linux文件I/O之文件共享

2.    文件共享几种情况

     (1) 执行open函数,都会创建一个新的文件表项,比如调用:

              fd1 = open(path, oflags);

              fd2 = open(path, oflags);

              则fd1和fd2分别指向不同的文件表项,但给定的文件只有一个v节点表项,所以两个文件表项中的v节点指针会指向同一个v节点表项,3种数据结构的关系如图:

linux文件I/O之文件共享

          在不同进程中打开同一个文件情况是类似的,都会得到一个新文件表项,共享同一个v节点表项,3种数据结构关系如图:

linux文件I/O之文件共享

        (2)执行dup函数,或者fcntl函数(其中的F_DUPFD或F_DUPFD_CLOEXEC命令),会共享文件表项,比如调用:

                  fd1 = open(path, oflags);

                  fd2 = dup(fd1);     //或者 fd2 = fcntl(fd1, F_DUPFD, 0);

                  fd1和fd2指向同一个文件表项,3种数据结构关系如图所示:

linux文件I/O之文件共享

           (3)执行fork函数,父进程中所有打开的文件描述符都被复制到子进程中,既然是复制文件描述符,那么跟执行dup的效果是一致的,父子进程会共享文件表项,例如父进程有3个不同的打开文件,fork建立子进程后,3个数据结构的关系如图所示如图所示:

linux文件I/O之文件共享

3.    总结

       只要是复制文件描述符的操作(如dup, fcntl的F_DUPFD,fork),都会共享文件表项;

       同一个文件每执行一次open,都会生成新的文件表项,每个文件表项的当前文件偏移量是独立的,在此情况下向同一个文件写数据可能会有问题:

        比如两次open同一个文件得到fd1和fd2,其文件偏移量均指向文件开头;先用fd1向文件写入一些数据,fd1文件表项中的偏移量会更新,但fd2文件表项中的偏移量不变。然后用fd2向文件写入数据,因为此时fd2文件表项的偏移量仍指向文件开头,所以写入的数据会把先前通过fd1写的数据覆盖。