Advanced Programming in UNIX Environment Episode 13

来源:互联网 发布:ps修复软件下载 编辑:程序博客网 时间:2024/05/29 17:56

文件共享
内核使用3中数据结构表示打开文件,他们之间的关系决定了文件共享方面的一个进程对另一个进程可能产生的影响。
(1)每个进程在进程表中都有一个记录项,记录项中包含一张打开文件描述表,可将其视为一个矢量,每个描述符占用一项。与每个文件描述相关联的是:
a. 文件描述符标识(close_on_exec);
b. 指向一个文件表项的指针。
(2)内核为所有打开文件维持一张文件表。每个文件表项包含:
a. 文件状态标志(读、写、添写、同步和非阻塞等);
b. 当前文件偏移量;
c. 指向文件v节点表项的指针。
(3)每个打开文件(或设备)都有一个v节点(v-node)结构。

Linux没有使用v节点,而是使用了通用i节点结构。虽然两种实现有所不同,但在概念上v节点与i节点是一样的。两者都指向文件系统特有的i节点结构。

假定第一个进程在文件描述符3上打开该文件,而另一个进程在文件描述符4上打开该文件。

  • 在完成每个write后,在文件表项中的当前文件偏移量即增加所写入的字节数。如果这导致当前文件偏移量超出了当前文件长度,则将i节点表项中的当前文件长度设置为当前文件偏移量(也就时是该文件加长了)。
  • 如果使用O_APPEND标志打开一个文件,则相应标志也被设置到文件表项的文件状态中。每次对这种具有追加写标志的文件执行写操作时,文件表项中的当前文件偏移量首先会被设置为i节点表项中的文件长度。这就使得每次写入的数据都追加到文件的当前尾端处。
  • 若一个文件用lseek定位到文件当前的尾端,则文件表项中的当前文件偏移量被设置为i节点表项中的当前文件长度(注意,这与用O_APPEND标志打开文件是不同的。)。
  • lseek函数只修改文件表项中的当前文件偏移量,不进行任何I/O操作。
    函数pread和pwrite
    Single UNIX Specification包括了XSI扩展,该扩展允许原子性的定位并执行I/O。pread和pwrite就是这种扩展。
#include <unistd.h>ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
  • 调用pread是,无法中断其定位的操作。
  • 不更新当前文件偏移量

函数dup和dup2
下面两个函数都可以用来复制一个现有的文件描述符。

#include <unistd.h>int dup(int fd);int dup2(int fd, int fd2);

调用dup2(fd,fd2)等效于

close(fd2);fcntl(fd,F_DUPFD,fd2);

其实两者并不完全等同。具体差别如下:
(1)dup2是一个原子操作,而close和fcntl包括两个函数调用。有可能在close和fcntl之间调用了信号捕获函数,他可能修改文件描述符。如果不同的线程改变了文件描述符的话也会出现相同的问题。
(2)dup2和fcntl有一些不同的errno。

#include <unistd.h>int fsync(int fd);int fdatasync(int fd);void sync(void);

FreeBSD 8.0不支持fdatasync。
fcntl函数可以改变已经打开文件的属性。

#include <fcntl.h>int fcntl(int fd, int cmd,...);

函数有以下5种功能。
(1)复制一个已有的描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC)。
(2)获取/设置文件描述符标志(cmd=F_GETFD或F_SETFD)。
(3)获取/设置文件状态标志(cmd=F_GETFL或F_SETFL)。
(4)获取/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)。
(5)获取/设置记录锁(cmd=F_GETLK、F_SETLK或F_SETLKW)。

原创粉丝点击