前言
本章主要介绍内核用于所有I/O的数据结构,以及两个进程各自打开统一文件的数据结构和dup、dup2用来复制一个文件描述符的实例。
提示:以下是本篇文章正文内容,下面案例可供参考
一、内核I/O数据结构
内核使用3中数据结构表示打开文件,它们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。
(1)每个进程在进程表里面都有一个记录项,记录项中包含了一张打开文件描述符表,每个描述符占用一项,每个文件描述符相关联的是:
a.文件描述符标志;
b.指向一个文件表项的指针;
(2)内核为所有打开的文件维持一张文件表。每个文件表项包含:
a. 文件状态标志(读、写、添写、同步和非阻塞等);
b.当前文件偏移量;
c.指向改文件v节点表项的指针;
(3)每个打开文件都有一个v节点结构,v节点包含了文件的类型和对此文件进行各种操作函数的指针;
二、一个进程打开两个文件
下图给出了一个进程打开两个文件对应的3张表之间的关系。该进程有两个不同的打开文件:一个文件从标准输入打开(文件描述符0),另一个从标准输出打开(文件描述符为1)。
三、两个独立进程打开同一文件
下图给出了两个独立进程打开同一文件对应的3张表之间的关系,两个独立进程打开同一文件,一个进程在文件描述符3上打开文件,而另一个进程在文件描述符4上打开该文件,打开该文件的每个进程都获得各自的一个文件表项,但是对于给定的文件只有一个v节点表项,之所以每个进程都获得自己的文件表项,是因为这可以使每个进程都有自己的对该文件的当前偏移量。
四、函数dup和dup2
dup和dup2用来复制一个现有的文件描述符,函数接口如下:
#include<unistd.h>
int dup(int fd);
int dup2(int fd, int fd2);
由dup返回的文件描述符一定是当前可用的文件描述符的最小值,dup2中fd2指定新描述符的值,如果fd2已经打开,先将其关闭,这些函数返回的新文件描述符与参数fd共享同一个文件表项,如下图:
在此图中,我们假定进程启动时执行了newfd = dup(1);此函数执行时,文件描述符3可用,它们指向同一个文件表项,所以它们共享同一个文件状态标志以及同一个文件偏移量。
dup(fd);等效于fcntl(fd,F_DUPFD,0);
dup2(fd,fd2);等效于fcntl(fd,F_DUPFD,fd2); 不考虑原子操作下
五、fork之后父子进程
下图给出了fork之后父进程和子进程之间对打开文件的共享,fork的一个特性父进程的所有文件打开文件描述符都被复制到子进程中,对于每个文件描述符来说,就像执行了dup函数。父进程和子进程每个相同的打开文件描述符共享一个文件表项。
六、实例
1.假设一个进程执行下面3个函数调用:
fd1 = open(path,oflags);
fd2 = dup(fd1);
fd3 = open(path,oflags);
画出I/O结构图,对fcntl作用与fd1来说,F_SETFD命令会影响哪一个文件描述符?F_SETFL?
答案(示例):
fd1和fd2指向同一个文件表项,fd3有新的文件表项,但是v节点与fd1和fd2一样,F_SETFD只影响fd1,因为标志位的作用范围是文件描述符;F_SETFL影响fd1和fd2,因为作用范围在文件表项中的文件状态标志。
总结
本文章主要介绍了I/O在内核中的结构,主要分为三个结构,分别是进程表项、文件表项、v节点表项,并给出一个进程打开两个文件、两个独立进程打开同一个文件、dup后的描述符的I/O分布图、父子进程后的结构体,以及给出了一个实例提供给读者理解。