内核使用三种数据结构表示打开的文件,它们之间的关系决定了多进程的文件共享操作。
(1)进程表:每个进程在进程表中都有一个记录项,记录项中包含有一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项,与之关联的是文件描述符标志,和一个指向文件表项的指针。
(2)文件描述符表:内核为所有打开文件维持一张文件表,每个表项包含文件标志,当前偏移量,指向该文件V节点表项的指针。打开某文件的每个进程得到一个该文件表项。
(3)V节点:每个打开的文件都有一个V节点结构。(保存在磁盘里,读入内存的)。Linux中没有V节点的概念,i节点就是V节点,对于一个给定文件,i节点只有一个。
三者关系如下图,当一个进程打开两个文件时
当两个独立进程各自打开同一个文件时,如下图
文件描述符标志:只用于一个进程的一个描述符
文件状态标志:适用于指向该给定文件表项的任何进程中的所有描述符。
6.dup和dup2函数
这两个函数都可以用来复制一个现存的文件描述符,原型
- #include <unistd.h>
- int dup(int fd);
- int dup2(int fd, int fd2);
①dup返回的一定是当前可用的最小文件描述符。
②dup2用fd2指定新描述符的值,如果fd2已经打开,则先关闭fd2,如果fd2=fd,则返回fd2,而不关闭。
这些函数返回的新文件描述符与参数fd,共享同一个文件表项,共享同一个文件状态标志,当前偏移量等。
③dup(fd)--->fcntl(fd,F_DUPFD,0)等效
④dup2(fd,fd2)--->close(fd);fcntl(F_DUPFD,fd2);
不完全等效,dup2()是原子操作
7.sync,fsync,fdatasync三个函数
传统的UNIX实现在内核中设有缓冲区高速缓存或页面高速缓存,大多数磁盘I/O都通过缓冲进行。
当将数据写入文件时,内核先将该数据复制到其中一个缓冲区中,如果该缓冲区尚未写满,则不将其排入输出队列,而是等待写满或内核需重用该缓冲区存放其他磁盘块数据时,将该缓冲排入输出队列,然后待其到达队首时,才进行实际的I/O操作。这种输出方式---延迟写。
延迟写减少了磁盘读写次数,但却降低了文件内容的更新速度。为了保证磁盘上的文件跟告诉缓存区数据内容一致性,UNIX提供了sync,fsync,fdatasync三个函数
点击(此处)折叠或打开
- #include <unistd.h>
- int fsync(int fd);
- int fdatasync(int fd);
- void sync(void);
sync:将所有修改过的块缓冲区排入写队列,然后返回,不等待实际写磁盘操作结束。守护进程update会周期性的调用sync,sync命令也是调用sync函数。
fsync:只对fd指定的单一文件起作用,并且等待写磁盘操作完成。fsync可用于数据库这样的应用程序,该类程序要求修改过的快立即写到磁盘上。
fdatasync:类似于fsync,但只影响文件的数据部分,fsync除数据外,还会更新文件的属性。
fdatasync在FreeBSD和Mac OS X中不支持。
8.fcntl函数
改变已打开文件的属性,原型
- #include <fcntl.h>
- int fcntl(int fd,int cmd,.../*int arg*/);
123
阅读(1139) | 评论(0) | 转发(0) |