linux系统文件流、缓冲及描述符与进程间关系详解
来源:岁月联盟
时间:2011-10-29
linux(unix)进程与文件的关系错综复杂,本教程试图详细的阐述这个问题。
包括:
1、linux多/单进程与多/单文件对于文件流和描述符在使用时的关联情况及一些需要注意的问题。
2、fork,vfork流缓冲等对文件操作的影响。
1、linux文件系统结构
首先补充一点基础知识,了解一下linux文件系统。如下图所示:
图1 磁盘,分区和文件系统
应该明白,上图所示结构是硬盘中文件存放方式的一种逻辑表现形式,与进程无关。对于其中一些术语,见下面的解释。
i节点:包含文件/目录的几乎全部-适用于放置在硬盘上的,需要长久保存的信息。
例如:文件所有者,文件类型,i节点号(存放在目录块中),主次设备号,连接计数,访问/修改时间,IO块长,文件字节数等等。
可以用stat函数(#include <sys/stat.h>)获取相关i节点信息信息。
2、简单的进程与文件关系
下面,我们了解一下单进程多文件以及多进程单文件间的关系,在不考虑fork(父子进程)的情况下,除了赋值语句给我们带来一些小麻烦以外,这个问题还是相当容易的。
2.1、一个进程同时打开多个文件:
图2 一个进程同时打开2个不同文件时内核数据结构
其中,v节点我们几乎已经介绍过了,因为它除了包含i节点之外,自身的内容实在是不怎么多,重点看一下文件表吧。
对于文件表,要注意,它并不是从在于硬盘中的东西,可以说,他是进程的一部分(可能是由操作系统内核负责维护,本人未考证,因为它到底是进程的还是内核的,对于我们要探讨的问题无关紧要)。文件表包括:
文件状态标志:包含读,写,添写,同步和非阻塞等各种文件打开/当前状态。
V节点:文件类型和对此文件进行各种操作的函数的指针,这些信息都是在打开文件时候由磁盘读入内存的。
I节点:同上节所述。
可用fcntl函数(#include <fcntl.h>)修改文件表内容。
2.2、多个无关联进程同时打开一个文件:
图3 两个进程同时打开同一个文件时内核数据结构
此时,2个文件分别使用不同的文件表,这说明不同进程间文件状态标志,文件偏移量等都是独立的。但他们共用同一个v节点表。对于这种结构的特性,理解起来因该是个轻松的事情。
3、文件描述符或流的复制
对于文件描述符或流的复制,很多情况我们会采用赋值语句,下面了解一个赋值和dup的不同之处,dup函数复制文件描述符后的内核数据结构:
图4 执行dup函数(#include <unistd.h>)复制文件描述符后,内核数据结构。
此时,2个fd文件标志同时使用同一文件表。
3.1、dup与赋值语句用于文件描述符的区别
为了了解dup与赋值语句用于文件描述符的区别,请看如下程序。
程序描述:
打开一个文件描述符,分别适用dup和赋值语句进行复制,复制之后,打印原始和被复制的文件描述符id,看看是否具有相同的值,然后关闭文件,测试关闭是否成功。
程序示例:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int sys_err(char *str)
{
puts(str);
exit(0);
}
int main(void)
{
int p,q;
if((p=open("c_fid.c", O_RDONLY)) == -1)
sys_err("open error");
q = dup(p);
puts("dup:");
printf("file p,q fd is:%d %d/n", q, p);
printf("close file p ok?: %d/n", close(p));
printf("close file q ok?: %d/n", close(q));
if((p=open("c_fid.c", O_RDONLY)) == -1)
sys_err("open error");
q = p;
puts("=:");
printf("file p,q fd is:%d %d/n", q, p);
printf("close file p ok?: %d/n", close(p));
printf("close file q ok?: %d/n", close(q));
return 0;
}
程序运行结果:
dup: