Chinaunix首页 | 论坛 | 博客

fx

  • 博客访问: 1372489
  • 博文数量: 115
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 3964
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-02 14:36
文章分类
文章存档

2022年(2)

2019年(2)

2018年(10)

2017年(1)

2016年(50)

2015年(12)

2014年(9)

2013年(29)

分类: C/C++

2013-05-07 11:27:02

这里我们需要先说明一下,我们这里所说的文件共享并不是一般意义上的
两个进程可以对同一个文件进行读写。而是共享同一个文件表。就是说
这个文件的当前偏移量。文件状态标志等信息是共享的。下面我们就具体介
绍这种共享。
我们还要说明一下unix内核中关于打开文件的内核数据结构。
中给出了们的关系模型,如图所示。(linux中没有使用v节点而是使用一个独立于文件系统的i节点和一个依赖于文件系统的i节点。独立的i节点和v节点指向系统特有的i节点。)




这里的关系图只是一个忽略细节的简单模型。
从上图我们看到:
   1每个进程在进程表中都有一个记录项。
记录项中包含有一张打开的文件描述符表。该描述符表中记录了每个打开文
件的文件描述符标志(当前只定义了一个文件描述符标志fd_cloexec,它指
明exec时是否关闭该文件描述符,默认时关闭该标志的。)和指向一个文件表
的指针。
  2内核为每个打开文件维持一个文件表。其中包含文件状态
标志(如open函数中介绍的o_append  o_sync 等标志),当前文件偏移量和v节点指针。
  3每个打开的文件都有一个v节点。其中包含了i节点信息,文件类型等。




现在我们先举个"不共享"(指文件表项)的例子。
如果两个进程都打开了一个相同的文件。那么内核中关于该文件的数据结
构如图所示




也就是说打开该文件的每个进程都有自己的文件表。那么每个进程也就拥
有他们关于该文件的自己的文件状态标志。比如说a进程此时调用read读取
三个字节,那么a进程所关联的文件表中的当前文件偏移更新为三,但是因
为b进程也拥有它自己的关于该文件的文件表,那么对b来说当前文件偏移量
仍旧是在文件头处。与a进程无关,他们互不影响。这也是造成进程间数据覆
盖的原因。因为a进程写了数据到文件中只影响了自己的文件表而不影响b进程
的文件表。那么b进程写数据到文件时就会从头开始写造成数据被覆盖。


那么什么时候两个文件描述符能够指向同一个文件表项呢。
这就是dup和dup2函数的作用的
#include
int dup(int filedes);
int dup2(int filedes, int filedes2);
这两个函数都可以用来复制一个现存的文件描述符
dup函数返回的新文件描述符一定是当前可用文件描述符中的最小值。
dup2函数可以用filedes2参数指定新描述符的数值。如果filedes2已经打开,则
先将其关闭。如果filedes2等于filedes.则dup2返回filedes2而不关闭它(其实就是没做什么事)

dup后的内核数据结构如下

下面我们来用 dup函数做个简单的测试


文件test的内容为“abcdefghij”


10         fd=open("test",O_RDONLY);
 11         nreads=read(fd,buf,3);
 12         buf[nreads]='\0';
 13         printf("fd=%d\n",fd);
 14         printf("%s\n",buf);
 15 
 16         int new_fd;
 17         new_fd=dup(fd);
 18         nreads=read(new_fd,buf,3);
 19         buf[nreads]='\0';
 20         printf("new_fd=%d\n",new_fd);
 21         printf("%s\n",buf);




程序输出如下
fd=3
abc
new_fd=4
def


从输出我们不难看出,现在 文件描述符 3 和 4 是共享同一个文件表的。


到这里不知道大家有没有考虑过一个问题,这里的文件表共享是在同一个进程中
不中的文件描述符共享同一个文件表。那么不同的进程间怎么共享呢


我自己做了一个测试,只是让a进程简单的输出他打开的文件描述符,然后读取
 一一些数据并输出,之后a进程休眠一段时间,这段时间b进程根据a的输出来得
到文件描述符,并在内部调用dup()函数复制.但是dup函数会出错返回。


那么如何能让两个不同间的进程传递文件描述符呢。那就需要用到一种IPC机制
并调用ioctl(fd,I_SENDFD,fd_to_send)  (fd为某种IPC产生的描述符或id)函数
进行传递。这两个主题我们在这里就不讨论了。                                  


最后需要注意的一点是 dup()函数复制的新描述符的标志 (当前只定义了一个
FD_CLOEXEC(执行时关闭))会被清除。即新描述符调用exec系列函数时不会被关闭

阅读(3046) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~