• [转]文件描述符


    1. 文件描述符的本质是数组元素的下标

    Alt text

    右侧的表称为i节点表,在整个系统中只有1张。该表可以视为结构体数组,该数组的一个元素对应于一个物理文件。

    中间的表称为文件表,在整个系统中只有1张。该表可以视为结构体数组,一个结构体中有很多字段,其中有3个字段比较重要:


    1. file status flags:用于记录文件被打开来读的,还是写的。其实记录的就是open调用中用户指定的第2个参数
    2. current file offset:用于记录文件的当前读写位置(指针)。正是由于此字段的存在,使得一个文件被打开并读取后,下一次读取将从上一次读取的字符后开始读取
    3. v-node ptr:该字段是指针,指向右侧表的一个元素,从而关联了物理文件。

    左侧的表称为文件描述符表,每个进程有且仅有1张。该表可以视为指针数组,数组的元素指向文件表的一个元素。最重要的是:数组元素的下标就是大名鼎鼎的文件描述符。

    open系统调用执行的操作:新建一个i节点表元素,让其对应打开的物理文件(如果对应于该物理文件的i节点元素已经建立,就不做任何操作);新建一个文件表的元素,根据open的第2个参数设置file status flags字段,将current file offset字段置0,将v-node ptr指向刚建立的i节点表元素;在文件描述符表中,寻找1个尚未使用的元素,在该元素中填入一个指针值,让其指向刚建立的文件表元素。最重要的是:将该元素的下标作为open的返回值返回。

    这样一来,当调用read(write)时,根据传入的文件描述符,OS就可以找到对应的文件描述符表元素,进而找到文件表的元素,进而找到i节点表元素,从而完成对物理文件的读写。

    2. fork 对文件描述符的影响

    fork会导致子进程继承父进程打开的文件描述符,其本质是将父进程的整个文件描述符表复制一份,放到子进程的PCB中。因此父、子进程中相同文件描述符(文件描述符为整数)指向的是同一个文件表元素,这将导致父(子)进程读取文件后,子(父)进程将读取同一文件的后续内容。

    案例分析(forkfd.c):

    1. #include <stdio h="">  
    2. #include <stdlib h="">  
    3. #include <fcntl h="">  
    4. #include <sys types="" h="">  
    5. #include <unistd h="">  
    6. #include <sys types="" h="">  
    7.   
    8. int main(void)  
    9. {  
    10.        int fd, pid, status;  
    11.        char buf[10];  
    12.          if ((fd = open("./test.txt", O_RDONLY)) < 0) {  
    13.                  perror("open");  exit(-1);  
    14.         }  
    15.          if ((pid = fork()) < 0) {  
    16.                perror("fork");  exit(-1);  
    17.         } else if (pid == 0) {  //child  
    18.                 read(fd, buf, 2);  
    19.                 write(STDOUT_FILENO, buf, 2);  
    20.         } else {  //parent  
    21.                  sleep(2);  
    22.                 lseek(fd, SEEK_CUR, 1);  
    23.                 read(fd, buf, 3);  
    24.                  write(STDOUT_FILENO, buf, 3);  
    25.                  write(STDOUT_FILENO, " ", 1);  
    26.         }  
    27.          return 0;  
    28.  }  
    29.   
    30. </sys></unistd></sys></fcntl></stdlib></stdio>  



    假设,./test.txt的内容是abcdefg。那么子进程的18行将读到字符ab;由于,父、子进程的文件描述符fd都指向同一个文件表元素,因此当父进程执行23行时,fd对应的文件的读写指针将移动到字符d,而不是字符b,从而24行读到的是字符def,而不是字符bcd。程序运行的最终结果是打印abdef,而不是abbcd。

    相对应的,如果是两个进程独立调用open去打开同一个物理文件,就会有2个文件表元素被创建,并且他们都指向同一个i节点表元素。两个文件表元素都有自己独立的current file offset字段,这将导致2个进程独立的对同一个物理文件进行读写,因此第1个进程读取到文件的第1个字符后,第2个进程再去读取该文件时,仍然是读到的是文件的第1个字符,而不是第1个字符的后续字符。

    对应用程序员而言,最重要结论是: 如果子进程不打算使用父进程打开的文件,那么应该在fork返回后立即调用close关闭该文件。

     

    转自:http://blog.csdn.net/u013078669/article/details/51172429

  • 相关阅读:
    hdu1003 最大子串和
    cf339d Xenia and Bit Operations
    A + B Problem II
    中国近代史纲要----王洪兵--2016年春季学期----中国海洋大学
    CodeForces 35D Animals
    CodeForces 558D
    Vanya and Brackets
    spfa
    hdu 1217 Arbitrage
    CodeForces 1A Theatre Square
  • 原文地址:https://www.cnblogs.com/gardener/p/7894641.html
Copyright © 2020-2023  润新知