码迷,mamicode.com
首页 > 系统相关 > 详细

Linux编程---I/O部分

时间:2014-06-17 23:09:52      阅读:342      评论:0      收藏:0      [点我收藏+]

标签:linux编程   io   内存   

很多函数都可以在网上找到,也比较基础,所以原型只给出了函数名.具体用到再man吧.

输入输出是个很重要的一块内容.几乎网络相关的东西基本都是靠底层IO调用来实现的.

好吧.还是先踏踏实实的介绍一下C标准库中的IO函数吧.个别函数我也是第一次见.对于不太常见的我就多解释一下,反正通常这些函数百度一下就清楚了,我就不多解释了~

1.C标准库IO函数

1.1流的关闭开启与重定向

fopen:打开一个流

fclose:关闭一个流

freopen:重新打开一个流

 

1.2 读与写

:

fgetc   getc  getchar  fgets  gets  getline  getdelim  fread

 

:

fputc  putc  putchar  fputs  puts  ungetc(这个叫读回退..写一个字符到输出缓冲流里)  fwrite

 

1.3 文件定位

ftell :告诉文件指针的位置

fseek: 指定文件指针的位置

rewind: 将文件指针指向文件开头

fgetpos: 返回当前的文件指针的位置,并通过参数传回

fsetpos: 设置文件指针的位置

后面两个应该很少用吧..相对来说,一般都是通过相对位置来找,而不是绝对位置来找.

 

1.4 文件结束和错误指示器

ferror: 当且仅当流的错误指示器被设置,返回0

feof: 当到达文件结尾,结束条件指示器被设置,返回0

clearerr: 用于清除上面两个函数的指示器

这里的指示器是每个流对象内部的标志变量.没怎么用过这两个函数..不太清楚为什么要有clearerr这个函数..难道是为了忽略错误继续执行?

 

1.5 流缓冲

setbuf: 用于设置打开或关闭流的缓冲.这里的缓冲都是调用者提供的内存.

setvbuf: 这个除了指定哪里为缓冲外,还可以指定缓冲类型(全缓冲,航缓冲,无缓冲).

我想一般情况下用setbuf就行了吧~

说道流,就不得不提刷新了.特别是多线程的情况下.刷新是必备的~

fflush: 刷新流的缓冲区.

其实我也是才知道,在行缓冲下,换行符可以代替fflush~

 

 

1.6 格式IO

其实这个完全可以放到上面的读写当中去.但是书上是这么写的,所以我也这么总结吧.

输出:  格式为%[posp$][flags][width][.prec][size]fmt

printf  fprintf  sprintf

输入:  格式%[posp$][*][width][size]fmt

scanf  fscanf  sscanf

格式什么的对于C比较熟的我就不说明了.基本就是那些,如果记不起来的百度看看~

 

1.7 临时文件

tmpnam: 返回一个合法的临时文件名,这个文件一定在/tmp下建立.

tempnam: 功能比上面多一点,可以指定文件存放目录

tempfile: 可以避免竞争的创建临时文件(多线程同时使用tmpnam).进程结束自动关闭~

我还专门查了一下,发现标准C中是真有这个函数的.这对于运行中的进程来说很方便啊~

 

2. 低级IO

2.1 创建,关闭和打开文件

create  open  close

字面意思很明显了.所以用法就不多说了.这里关键是要了解打开文件后其在内核中管理的形式是如何的.

1) 这几个函数返回的都是一个int类型的值,叫做文件描述字.这个值是按最小未分配的文件描述字来优先分配的.所以你一开始打开了1号文件描述符,那么关闭之后,再打开其他文件,那么文件描述符就是1.

 

2) 由于系统为了保证读写一致性的问题,会在内核中统一设立一个打开的文件表.并且每个流都有一个指向其表项的指针.然后每个系统打开文件表中,又有一个指针指向一个vnode的文件信息结点.

文件表项会记录文件的状态与文件指针位置信息,vnode则只记录文件的基本信息(包括内容,文件大小和具体的磁盘上对应的记录位置,即包含inode上的信息).

虽然两个指针麻烦多了,不过这样分开之后,对于文件系统的要求就降低了.可以直接通过vnode这种统一的格式来操作文件呢.并且这个vnode是以文件打开才建立,而是针对每个文件,意思就是不同进程打开同一文件,必定使用相同的vnode.

 

3) 对于fork出来的子进程,所有的东西都会继承.所以也包含这个文件描述符和文件表项~

由于只复制进程中的资源,所以复制的是文件表项的指针~

 

2.2 读与写

read  write

linux的函数写的真是太标准了....想让人望文生义都难啊...

这个我也就不多说了,具体的百度吧``

 

顺带附上lseek这个设置位置的函数.其实跟fseek差不多,所以也没什么好说的.

不过要注意这个函数返回off_t,fseek返回int.

并且都可以把文件指针指向文件最大值之外,造成空洞.

 

2.3 重定向

dup: 复制描述字到一个新的描述字.即增加一个文件描述符描述同一个文件表项

dup2 把一个文件描述字所指的文件表项换成另一个文件描述字所指文件表项.即重定向

这个函数阐释了重定向的根本.只是修改文件描述符的指针所指向的文件表项.

2.4 文件描述符与流的转换

fdopen: 给它一个文件描述字,还你一个文件流!

fileno: 给它一个流,它就给你一个文件描述字

 

2.5 文件控制函数

fcntl: 对已打开的描述字进行操作.

其实就是修改文件表项中的信息.不过应该不止如此,书上还写有文件锁.所以我认为应该部分vnode内容也可以被修改.

具体用法也很多,主要有下面三条:

1) 重复文件描述字

2) 文件描述字标签,也就是包含描述字对应指针的那个结构体(这纯粹是我自己的理解,不对还请指正).

3) 文件状态标签.这个就多了.什么读写啊,追加啊,都可以通过这个函数更改和查看.

 

我自己也没怎么用过这个函数,毕竟不写库,文件的状态基本都是清楚的,没必要再改或者查询.

 

2.6 分散读和收集写

readv: 用于将自己文件中的连续信息,发到多个地址中去.

writev: 把多个地址的信息,写到自己的文件里面来.

这两个函数估计也就只有搞服务器开发的会用到了吧..

貌似UDP广播可以用这个实现.

 

2.7 清理内核IO缓冲区

fsync: 将文件修改的内容从内核缓冲区写到磁盘中去

fdatasync: 比上面功能好一点,只把修改过的数据写到磁盘中.所以一般比fsync.

这里理一下.内核缓冲区也是分IO.对于O而言,用的是上面提到的输出缓冲.

关于I的部分.我个人认为很可能没有占用内核空间,而是直接用的read参数的地址.

当然,这还是得看了源码才知道是怎么回事.

 

3.文件相关

这一部分其实和函数调用相关的比较少,主要是一些概念性的东西.

 

3.1 文件

前面提到过vnode.不过在实际磁盘上用于保存信息的是inode.由于linux有虚拟文件系统VFS,统一了下面的文件系统接口.所以实际运行过程中就创建的vnode.inode就是实际的ext文件系统中的内容了.

这个inode,包含了文件的属性信息.具体有文件的类型,所属的角色关系,访问权限,时间戳.

如果想要查看相关信息可以使用stat,fstatlstat.

这三个函数的差别在于fstat直接用文件描述符访问.statlstat用路径来访问.并且对于符号链接来说,stat返回的是符号链接所指的文件,lstat返回的是符号链接本身的信息.

 

3.2 文件类型

1) 普通文件.绝大部分文件都是这个.一般的存储字符的文件和二进制文件都是这个类型.访问方式靠的访问它的程序约定.

2) 目录.就是windows下的文件夹.但是对于用户不能写目录,只有内核可以(估计就是只能用系统调用写吧).

3) 链接文件.linux下有两种链接方式.

一种是硬链接,即只有链接数为0才删去的链接.但是有局限性,一是是不能跨越文件系统.二是只有root才能创建目录的硬链接.

可以用link函数来创建硬链接

另一种,符号链接.这个和windows的快捷方式很像.源文件删了就会提示找不到快捷方式.这种链接只保存一个源文件的路径名.所以连文件名都不需要了..

4) 特殊文件 

这个也称为设备文件.设备文件不含数据,它们的作用是将物理设备映射到文件系统中的文件名.可以用mknod函数来创建,并且与内核的一个软件相连,这个软件就是设备驱动程序.

这种特殊文件也分为两种:

--块文件 ls -l中的b文件

块文件主要是按固定大小且可随机访问的块来存储和执行I/O,常见的有硬盘什么的.

只有块设备才能包含文件系统~

--字符文件  ls -l中的c文件

可以存储和传送任意大小的数据.这个主要是串行设备,如显示器,鼠标和键盘之类的.

 

这本书上写的还蛮清楚的.我记得好像是鸟哥的还是什么书,这里写的愣是没看明白差别.

 

5) socketpipe文件

这两种文件到时候写管道还有网络相关的东西再写吧.毕竟这不是一两句能搞定的~

 

 

3.3 文件的所属角色关系和用户组

主要分为--实际--有效--设置 这三种用户和租.我简单的说明一下,这三个权限是针对正在运行的进程而言的.

实际RUID ---就是正在使用该文件的进程.

有效EUID---就是根据这个ID判断它有什么属性,然后给与这个ID对这个文件的权限

设置SUID---这个主要是让权用的.即在执行这个文件的时候,执行者拥有和文件所有者相同的权力.即只要有可执行的权限,就可以拥有文件所有者的对文件的权限.

 

这里RUIDEUID中的ID包含组ID和用户ID.

有三个函数可以来让进程使用:chown,fchown,lchown.

其中对于文件的所有者关系的改变,只能是通过root来改变.具体的也是很多宏参数,我也就不细说了.

 

3.4 文件权限

每个文件都有三个关系拥有者,所属组,其他人

还有另外三种权限,,执行

关系很明白了,权限我要说一下.

对于目录而言权限有不同的解读.

读权限:代表可以读目录内的信息,即目录中有哪些文件(注意,文件名的信息是在目录文件中记录,而不是一个文件一个文件翻出来的).

写权限:代表可以在目录内创建文件,重命名,删除目录内文件.

执行权限:这个是个特殊的概念,其实应该说是叫”检索权限”.只有有了这个权限,才能显式的去访问目录中的子目录或文件.如果没有读权限,只有写权限的话,你就只能靠完全路径名来访问文件了.

 

这里额外有一个sticky权限

这个主要是把用过的文件保留一个副本在swap区中.可以加速文件的打开工作.如果是程序,就加快程序的开启工作.同时在现代linux系统中,这个还起到了保护文件的作用.

保护作用有点复杂,主要是:

假如我所在的目录有写权限,那么我完全可以创建一个文件去覆盖一个只能读不能写的文件.

假设我有一个read文件对所有角色只有r权限,并且所在目录有写权限.那么按照下面来做:

cat read>temp

vi temp ;这里随便改改

mv temp read  ;选择y

cat read

你就会发现read的内容已经被改动了.

如果一个目录在上了stickly权限之后,那么这个目录下的文件只有文件所有者,目录所有者和root才能删除移动或重命名文件了.

 

3.5 确定和改变文件方式

1) 屏蔽字 

umask函数.这个估计写过shell脚本的都知道把..如果不改屏蔽字,那么创建的时候就是就会按照屏蔽字来屏蔽相应的权限位.

2) 改变权限

主要有两个函数:chmodefchmod

只有当有效用户ID等于文件用户ID时才能改,否则只有是root权限才能改

3) 判别进程是否原本就拥有这个文件的执行权限

access函数.可以根据要求判断当前进程是否具有这个文件的某种权限.

虽然stat也可以,但是access方便一些.参数用的路径.

 

3.6 文件大小

文件大小一般是16512的倍数(硬盘一个块是512字节,16我就不清楚了).

并且对于存储了大量空洞内容(0)的文件来说,linux会减少其占用的空间.

如果文件中有很多个0.那么就会在其中插入一个计数,来指定插入了多少个0.

 

关于截断文件

ftruncatetruncate两个函数.ftruncate是针对以写方式打开的文件来说的,参数是文件描述符.truncate参数则是路径,但同样进程要对截断文件有写属性.

 

3.7 文件时间

主要有三个指标:

st_atime:最近一次读或执行的时间

st_mtime:最近一次写文件的时间

st_ctime:最近一次改变inode的时间

这三个变量在stat结构体中定义了.可能有人认为mtimectime要一个就够了吧?但其实很多时候写文件是有写缓冲的.由于系统维护inode,所以inode的改变只用最后一次要写入磁盘的时候再改就行了.

 

如何更改文件的访问时间和修改时间?

utimeutimes函数

utime使用utimebuf结构体,这个里面只有atimemodtime.ctime只能被系统来修改,所以有这两个成员就够了.其中utime是以秒来计数的,utimes则是以微秒来计数.

utimes貌似资料很少,估计高实时系统,用微秒来计数还不如直接上汇编自己写定时程序吧.

我记得好像也在哪看过.linux的最小时间片是毫秒级的,这可能也是utimes用得少的原因.

 

3.8 文件的删除与改名

1) 删除函数unlink

unlink看上去不像是删除文件的函数.但是linux存在硬链接这一说,所以unlink也就很好理解了.当一个进程正在访问被unlink的文件时,如果调用了unlink这个文件,那么直到进程关闭这个文件,才会把文件删除.原来close系统调用会来检查这个文件链接数!

这里有一点就是必须有可以修改这个文件的权限才行.

还有就是对于普通用户,不能用这个来删除目录,只能用下面的函数

 

2) 删除目录函数rmdir

这个只能删除空目录

 

3) 真正的删除函数remove

就是unlinkrmdir的结合体

 

4) 改名函数rename

--必须有该目录的的写权限

--如果是文件,那么会删除所有硬链接  硬链接多的文件还是不要改名了..

--如果是目录,新名字可以是个已存在的空目录名.

--如果是符号链接,如果oldname是符号链接的路径名,那么符号链接被改名(符号链接本来的名字就是符号链接的路径名).如果newname是一个符号链接的路径名,那么原来的符号链接被删除.

 

 

3.9 工作目录

getwdgetcwd用于得到工作路径.第二个函数多一个参数来指明存放路径名数组的大小.要相对第一个安全一些.

chdirfchdir用于更改当前进程工作目录.第二个通过文件描述符来指明文件.

发现了没有?几乎所有带f的文件操作就相当于告诉你参数是用的文件描述符.

 

1) 创建目录函数mkdi

这个和shell指令差不多.也就不多说了.

2) 关闭与打开目录opendir--closedir

这里用的不是FILE结构,而是DIR结构.注意这里DIR的概念类似C中的流,而不是一个文件描述符.估计linux对目录文件特殊化处理了吧.

3) 目录项读取函数readdir

这里目录项是DIR中的结构.每个目录项用struct dirent这个结构体来表示.每次调用这个都返回一个目录项,然后DIR流指向下一个目录项.

这里的目录项就是我之前解释过的,目录中的文件名都存在目录项中.

 

4) 对DIR流的几项操作

类似FILE这个也有定位的函数.

rewinddir : 重定位DIR流到第一项

telldir : 返回当前位置

seekdir : 根据参数设置DIR流的值

 

 

4. 高级IO

4.1 文件锁

主要分为两种锁:

读锁:主要是为了防止在读的时候文件被别的进程改写

写锁:主要是为了保证写操作是原子操作.

 

注意,只有普通文件才需要下面这种锁,网络或中断文件不建议用这种锁.

函数用的就是fcntl.只是传给第二个参数的值为F_GETLK,F_SETLK,F_SETLKW.

1)F_GETLK 得到锁信息,文件的某个区域是否存在有碍于创建新锁的其他锁

2)F_SETLK 同时在第三个参数中加上F_RDLCKF_WRLCK.同时也可以用F_UNLCK清除.

3)F_SETLKW 和上面一样,只是它会一直阻塞进程知道完成设置或清除锁

文件锁也比较特殊,它锁的是文本的一部分.可以自己根据第三个参数来设置其锁的部分起点和长度

用锁的时候也多用readwrite,因为C标准库中的函数会自带缓冲,读入和写出的数据大小会与你自己写的不一样.

而且这个锁也是个建议锁,readwrite中并不强制性检查.所以只能在多个配合的进程同时用fcntl来检查.至于强制锁,首先要让文件系统用mount -o suid命令安装,并且文件本身设置了设置组ID且关闭了组的执行权限位的普通文件...

 

 

还有一些锁的相关信息,可能编程的时候会遇到:
1) 锁与进程是相连的.文件上的每一个记录所都关联一个进程ID.即锁不会被子进程所继承.

2) 锁只与文件相连而不与文件描述符相连.意思就是你用dup重定向描述符之后,锁会继承过去.个人理解锁在vnode,所以改变文件描述符并不改变其锁的设置.

 

 

4.2 信号驱动IO

其本质上还是同步IO,毕竟是用的信号中断.不过节省了时间去等待输入的阻塞循环.

Linux下有两个信号是用来驱动IO:SIGIOSIGURG.但后者只用于通知进程在网络链接上到达了带外数据.

如果在文件描述字上设置了O_ASYNC标志,那么文件描述字对应文件上有输入或者输出的时候,就会向进程发送一个信号.如果文件描述字对应一个终端设备,那么SIGIO则会发送给前台进程组,其他情况应当调用fcntl(fileds,F_SETDOWN,pid)来设置接受信号的进程或进程组.

 

具体使用信号驱动IO的步骤:

1) 调用sigaction()建立信号句柄

2) 调用fcntlF_SETDOWN来设置接受新号的进程或进程组

3) 如果要接受的新号是SIGIO,则必须调用fcntlF_SETFL命令设置文件描述字的O_ASYNC标志使其能够生成SIGIO信号

 

 

4.3 多路转接IO

参考的书中虽然介绍了select/poll,但是没有介绍epoll真是太遗憾了.epoll就我自己搜集网上资料写一写吧.

4.3.1 select函数

这个函数原理就是轮询,所以效率比较差,用的也比较少.

这个函数最后一个参数是时间,如果其中的内容全部为0,那么就是不等待.如果设置了NULL则是永远等待.其他情况都是按值来设置.虽然这个时间可以设置成微秒,但是如之前所说,Linux的最小时间片是以毫秒为单位的,书上说是10ms.

 

中间三个参数rfds,wfds,efds分别代表读,,例外条件.

也就是说,rfds中存放需要读的描述字.wfds存放需要写的描述字,efds用于检查外带数据.

rfds对应0~31号描述字,wfds对应32~63号描述字,efds对应64~95号描述字了(这就是为什么要晓得描述字的分配规则的原因吧)

 

select的中间三个参数都为NULL,其实这个就相当于是sleep...

 

这三个参数也需要使用相应的宏来设置.

FD_ZERO //清空为0

FD_CLR (fileds,fdset) //出去fileds描述字

FD_ISSET(fileds,fdset) //判断是否fileds在其中

FD_SET(fileds,fdset) //加入fileds描述字

 

select的返回值也有点特点:

>0 : 表示已经有文件就绪,准备读或写或额外数据了.给出就绪的描述字

=0 : 表示时间到了,仍然没有就绪..注意,这种情况下描述字集合会被清空!

-1 : 表示出现错误.例如当被信号中断.这时候并不改变描述字集合.

 

 

4.3.2 poll函数

这个函数本质上和上面相同,都是将一堆文件描述符统一来管理.知识参数不太一样.

这个函数的时间选项比较有特点.小于0,阻塞等待;等于0立即返回;大于0,其值为等待的毫秒数.基本已经被epoll取代了,所以不多说了.

4.3.3 epoll函数

早就听过这个函数效率高,但是一直没怎么接触过.这次写总结干脆就学一学吧.

这个函数有两种使用方法:

LT : 和前面的两种方法相似,IO就绪就去执行.并且内核会一直保持有IO就绪的这个状态.

ET : LT的差别就是不维持状态,只发送一次信号给进程.至于进程有没有处理,内核并不管.

使用起来也就三步:

1) 调用epoll_create.创建一个epoll的描述字.用于后续操作

2) 使用epoll_ctl,相当于select的集合操作.只是只是个专门的函数,而不是多个宏组成的.

描述参数依次为efds,op,fd,event.

efds就是creat返回的文件描述字.相当于一个集合.

op就是要对上面这个集合做得事情.

fd就是新加入这个集合的文件描述字.

event就是对这个新加的fd采取什么样的动作.

具体的描述还是用到的时候查手册吧.

上面所说的LT和ET在event中设置.

这里其实还有一个data联合体包含在event结构体中.event中的事件描述应该和data中对应的类型有对应关系吧.以后看nginx的时候再看看吧.

3) 使用epoll_wait来等待事件的发生

4) 调用close关闭第一步生成的文件描述字.

 

 

看网上的解释,这个函数真是各种厉害啊..

mmap不用说,直接映射,用过的都知道效率.

ET触发.网上比喻是沿触发.这个效率也是很nice的.

socket描述符数目是进程打开上限..这个比select不到100个真是屌炸天啊..

回调函数的伪AIO(下面讲的),只有活跃socket操作.这不知道要节省多少查询时间...

有时间还是看看底层实现吧.

 

4.4 异步IO

4.4.1 异步IO相关函数介绍

简单来说就是IO的时候进程并不阻塞.通过aio_read和aio_wirte向系统提交申请,然后由系统来排队,并由内核生成线程来运行异步IO控制块.完成后发送信号到进程,通知其IO完毕.下面是glibc中的异步IO的相关函数:

aio_read :这个很清楚了,就是读

aio_write:也很清楚...就是写

aio_error :用来检查IO是否成功完成.

aio_return : 获得IO的状态

aio_suspend :挂起进程,直到有一个请求已完成

aio_cancel :删除悬挂在文件描述字上的一个或多个请求

lio_listio :启动一组IO请求,和readv还有writev很像,可以减少进程内核间的切换次数       

aio_fsync :异步地将系统缓冲区中含有的文件已修改数据永久写到磁盘上.即强制同步

 

这里调用read和write要注意的是,异步io结束后,文件的当前位置是不确定的.必须用其IO结束返回值来更新文件的指针位置.

对于lio_listio来说,其请求数组中的顺序不一定是执行顺序,具体的修改优先级比较重要吧.每个IO操作完成后都会给进程发一个信号.当第一个参数选择LIO_NOWAIT时,所有的IO操作完成之后也会再发一个全部完成的信号.这里由于数组参数中结构体包含一个信号的结构体,所以是可以指定每个IO操作产生的信号的.

异步IO是在内核中进行的,所以无法使用之前同步IO中得到IO信息的方法.因此,每个异步IO都保持一个返回值和errno.并通过aio_error和aio_return来得到相关信息.我想主要用在信号在设置时候指定的函数中吧.对于aio_return来说,只要一执行,那么就会将其相关资源返回给系统.对于一个未完成的IO操作,说不定还会产生数据丢失.所以一般顺序是调用aio_error,然后确定状态后再调用aio_return.

aio_suspend则有点像lio_listio,但是它是阻塞完成的.只有当list中的IO请求至少有一个完成时,才会停止阻塞.或者出现一个信号时,或者时间参数设置的时间到了就停止阻塞了.

aio_cancel则是撤销一个异步IO请求.通过文件描述字来指定要删除的异步IO.其中第二个参数结构体中的fd信息必须与第一个参数相同.并且这个函数并不一定就能撤销其IO操作.还要看系统是否支持,或其IO操作进行的状态也不允许撤销.

aio_fsync则是与磁盘同步的函数,只要是带缓冲的情况,都会带有一个fsync同步的相关函数吧(不过标准C中貌似用fflush来同步的..).这个函数并不等待其同步的完成,只是发出一个请求来告诉内核需要写到磁盘上,但并不强制等待.这也就是异步IO的好处吧.在内核收到这个请求之后,会派生一个线程来将其请求立刻写的IO从缓冲区中取出,并且逐个写入磁盘.如果此时在调用一个aio_fsync的话,并不会再发一个请求,因为内核已经在开始执行了.

 

4.4.2 异步IO的一般使用步骤:

1) 调用open打开指定的文件,并获得文件描述字,并设置其文件指针所指向的内容的地址.

2) 创建并填充异步IO控制块aiocb

3) 如果使用信号,还要设置信号的句柄(即执行的函数指针)

4) 调用aio_相关的一些异步IO请求,或使用aio_sync来使其同步.

5) 如果应用需要等待IO的完成,那么可以用aio_suspend,或者一直使用aio_error来查询.

6) 完成异步IO之后调用aio_return函数

 

4.4.3 异步IO使用注意事项

1) 不要再对应的IO操作还未完成之前重复使用同一个AIO控制块.

linux中aiocb不仅存放了应用使用的成员,还包含了操作系统内部使用的成员,以及存放操作错误编码的成员和存放返回值的成员.

2) 必须自己管理异步IO文件的位置指针.

上面说道过,就不多说了.记得在在信号句柄中加return和lseek~

3) 不要对同一个文件描述字混合使用同步和异步IO

这样很危险,因为异步IO和进程是并行的.这样很可能导致文件指针的位置混乱.并且写的数据错位.当然你想用也可以,但是一定要清楚文件指针位置在哪里,并且别弄成并发的就行.

 

5. 存储映射IO

在之前的方法中,对于不同进程读同一个文件一直是对每个进程保留一个副本的(书上虽说vnode每个进程共享,并且保存inode信息).所以对于内存空间的浪费是比较大的.特别是网络应用,动不动成千上万个socket..所以mmap就随之诞生了.

5.1 mmap函数

使用这个函数的好处在于可以共享,并且映射之后,对于mmap的映射区域修改的操作也很迅速,毕竟直接操纵内存.这个函数实现的机制也和硬件接触比较多,比较底层,效率也就比较高了.再就是mmap每次映射都是以页为单位的.

这个函数还提供了一种私有的形式,这种形式比较特殊.往私有副本里面写东西并不会改变磁盘上的信息.只是在内存里面改着玩...

还有一个好处就是,全部进程共享同一片区域,那么更改是立即可见的.只要是一个进程一改,另外的进程就可以直接见到修改.既危险又高效.

 

只是要注意一点就是:mmap不会改变源文件的大小!

我以前编过一个程序就是准备靠mmap来写一个文件,还多个程序合作写...调试半天...最后查mmap的相关说明才发现原来不能扩充文件.....

还有一点就是mmap传的是文件描述字,所以你以什么方式打开的文件,才能针对mmap的页设置其子集的属性.

 

5.2 munmap和msync函数

munmap:这个函数就是用来解除映射的.但并不会指定让其写回到存储器.

msync:这个函数就是强制写回了.并且还可以配置写回的方式,异步或者同步.并且这个只能针对原mmap的区域是共享性的才能执行.

 

IO部分就写到这里了.虽说异步IO的底层函数没讲,但我觉得够用了.以后用到再补进来吧.

Linux编程---I/O部分,布布扣,bubuko.com

Linux编程---I/O部分

标签:linux编程   io   内存   

原文地址:http://blog.csdn.net/meiboyu/article/details/31376823

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!