系统编程手册 第五章 - DDL-Killer/The-road-of-Linxu-Group2024 GitHub Wiki

原子操作和竞争条件

  • 所有的系统调用都是以原子操作方式执行

以独占的方式创建一个文件

  • 确保检查文件和创建文件的步骤属于一个单一的原子(既不可中断)操作

向文件尾部追加数据

  • 需要将文件偏移量的移动与数据写操作纳入同一原子操作,在打开文件时加入O_APPEND标志可以保证这一点

文件控制操作:fcntl()

  • #include<fcntl.h> int fcntl(int fd,int cmd,...); return on success depends on cmd
  • 内核会根据cmd参数的值来确定该参数的数据类型

打开文件的状态标志

  • fcntl()的用途之一是针对一个打开的文件,获取或修改其访问模式和状态标志
  • 要获取这些设置,需要将fcntl()的cmd参数设置为F_GETFL
  • 判定文件的访问模式有些复杂,这是因为O_RDONLY(0),O_WRONLY(1)和O_RDWR(2)这三个常量并不与打开文件状态标志的中的单个比特位对应,所以需要使用掩码O_ACCMODE与flag相与,将结果与三个常量进行比对
  • accessMode = flags & O_ACCMODE;if(accessMode == O_WRONLY || accessMode == O_RDWR){printf("file is writable);}
  • 可以使用fcntl()的F_SETFL命令来修改打开文件的某些状态标志:O_APPEND,O_NONBLOCK,O_NOATIME,O_ASYNC,O_DIRECT
  • 使用场景:
    1. 文件不是由调用程序打开的,无法使用open()调用
    2. 文件描述符的获取是通过open()之外的系统调用
  • 为了修改打开文件的状态标志,可以使用fcntl()的F_GETFL命令来更新
  • 例子:int flags;flags = fcntl(fd,F_GETFL);if(flags==-1){errExit("fcntl")};flags |= O_APPEND;if(fcntl(fd,F_SETFL,flags)==-1){errExit("fcntl");}

文件描述符和打开文件之间的关系

  • 内核维护的三个数据结构
    1. 进程级的文件描述符表
    2. 系统级的打开文件表
    3. 文件系统的i-node表
  • 内核为每个进程维护打开文件描述符表--每一条目都记录了单个文件描述符的相关信息
  • 内核对所有打开的文件维护有一个系统级的描述表格--里面的各条目称为打开文件句柄,一个打开文件句柄存储了一个打开文件的全部信息
    1. 文件偏移量
    2. 打开文件时使用的状态标志
    3. 文件访问模式
    4. 与信息驱动I/O相关的设置
    5. 对该文件i-node对象的引用
  • 每个文件系统都会为驻留其上的文件建立一个i-node表
    1. 文件类型和访问权限
    2. 一个指针,指向该文件所持有的锁的列表
    3. 文件的各种属性,包括文件大小以及不同类型操作相关的时间戳

复制文件描述符

  • Bourne shell的I/O重定向语法 2>&1 ,意在通知shell把标准错误重定向到标准输出,因此,下列命令将把(因为shell按从左至右的顺序处理I/O重定向语句)标准输出和标准错误写入result.log文件 ./myscript > results.log 2>&1
  • shell通过复制文件描述符2实现了标准错误的重定向操作,因此文件描述2与文件描述符1指向同一个打开文件句柄,可以通过调用dup()和dup2()来实现此功能
  • #<unistd.h> int dup(int oldfd); return (new)file descriptor 假定在正常情况下,shell已经代表程序打开了文件描述符0、1和2,且没有其他描述符在用,newfd = dup(1) dup调用会创建文件描述符1的副本,返回的文件描述符编号值为3
  • #<unistd.h> int dup2(int oldfd,int newfd); return (new)file descriptor
  • dup2()系统调用会为oldfd参数所指定的文件描述符创建副本,其编号由newfd参数指定,若指定编号已打开,则dup2()会首先关闭
  • 也可以用fcntl()的F_DUPFD,newfd = fcntl(oldfd,F_DUPFD,startfd)该调用为oldfd创建副本,且使用大于等于startfd的最小未用值为描述符编号
  • 文件描述符的正、副本之间共享同一打开文件句柄所含的文件偏移量和状态标志,然而新文件描述符有其自己的一套文件描述符标志,且close-on-exec标志总处于关闭状态
  • #<unistd.h> int dup3(int oldfd,int newfd,int flags); return (new)file descriptor 目前dup3()只支持一个标志O_CLOEXEC,这将促进内核为新文件描述符设置为close-on-exec标志(FD_CLOEXEC)
⚠️ **GitHub.com Fallback** ⚠️