0%

《操作系统》Linux之文件描述符

在Linux系统中一切皆可以看成是文件,文件又可分为:

  • 普通文件
  • 目录文件
  • 链接文件
  • 设备文件

文件描述符

文件描述符是一个整型数字,从0开始。windows中文件描述符被称为文件句柄

其实就是打开文件表数组的下标,下面看什么是打开文件表

打开文件表

打开文件表是内核维护的一个数组,代表整个系统中已经被打开的文件(一个文件可以被打开多次,即多个元素可以指向同一个i-node),每个元素包含了下面信息:

  1. 当前文件偏移量(调用read()和write()时更新,或使用lseek()直接修改)
  2. 打开文件时所使用的状态标识(open()的flags参数,比如O_APPEND标识)
  3. 文件访问模式(如调用open()时所设置的只读模式、只写模式或读写模式)
  4. 与信号驱动相关的设置
  5. 对该文件i-node对象的引用
  6. 文件类型(例如:常规文件、套接字或FIFO)和访问权限
  7. 一个指针,指向该文件所持有的锁列表
  8. 文件的各种属性,包括文件大小以及与不同类型操作相关的时间戳

打开文件表前3个元素会被内核启动时填充,第1个元素是标准输入,对应文件/dev/stdin,第2个元素是标准输出,对应文件/dev/stdout,第3个元素是标准错误,对应文件/dev/stderr

其文件描述符分别是0、1、2,就是数组下标。这3个文件描述符可以直接被所有进程使用

如果又一个新的文件被打开,则它的文件描述符会是3

i-node表

i-node表也是内核维护的一个数组,每个元素代表一个文件,包含了文件类型、文件锁等信息

下图是对应关系

多个进程写同一文件会发生什么

首先要明白:每一个系统调用都是原子性的,操作系统内核保证这一点

如果多个进程使用write系统调用写同一个文件,因为系统调用都是原子性的,所以两个进程写的内容不可能交叉存在,而只可能是互相覆盖(因为没有使用lseek系统调用来改变偏移)

如果多个进程需要相继附加内容,则这些进程都要同时使用lseek系统调用和write系统调用才行。但这两个系统调用整体并不是原子性的,所以会出现覆盖,而不会正常的相继附加内容,所以这里必须使用锁机制将两个系统调用锁住,保证他们的原子性。

而内核提供了更简便的方式实现上面的需求,就是打开文件时传递O_APPEND标识,内核会负责将lseek和write原子化




微信关注我,及时接收最新技术文章