Unix编程 - IO 小结.doc_第1页
Unix编程 - IO 小结.doc_第2页
Unix编程 - IO 小结.doc_第3页
Unix编程 - IO 小结.doc_第4页
Unix编程 - IO 小结.doc_第5页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Unix编程 I/O1 关于 Unix I/O系统为每个进程都维护一份打开文件的文件列表,表中每个元素的内容包括指向文件备份inode的指针以及元数据(文件状态、位置等)。该列表由文件描述符来索引,文件描述符是非负数,一般一个进程的上限是1024,-1是非法值。子进程会得到父进程的一份文件列表的拷贝,也就是说,则进程继承了父进程多有打开的文件状态。2 Unix 提供的基本I/O2.1 常用函数作为Unix系统提供的基本系统调用,主要有以下接口,都是基于文件描述符的:l open / read / write / close / lseek l fsync / fdatasyncl poll / selectl 其他,包括文件截短等2.2 主要接口的关键特性及注意事项2.2.1 readl 首先,我们要考虑返回值。1. 正常情况下,返回length 为预期读取的数据长度。2. 当0 length 预期长度,可能有以下几种情况:系统调用被中断抢占,发生一般错误,读到预期长度前就已经读到了EOF。3. 返回 0 ,表示读到了EOF。4. 返回 -1,表示发生了错误。l 为了保证读到所有数据,应当进行特殊处理用一个循环来进行read调用,每次读出的长度进行累加,直到达到预期长度。当然如果中间发生了错误,应当参见下一条进行处理。l 当发生错误时,我们需要检查errno值1. EINTR,表示被中断打断,应当重新读取2. EAGAIN,表明由于没有数据读而使得read调用被阻塞,应当在稍后重新读取l 关于非阻塞读这里的非阻塞,不是指阻塞系统调用,而是当没有数据可读的时候,进程不会因此而挂起,导致无法处理其他的指令。应当由应用程序来保证当read调用被阻塞后,能够在稍后重新唤醒。2.2.2 writel 首先,我们也是要考虑到几种特殊情况1. 部分写,这个和read类似,需要用循环来保证2. 追加写,这个是表明始终在文件末尾写入,(多进程,日志)3. 非阻塞写,通常不会出现,处理和非阻塞读类似l 重要的是,要明确write的行为write实际上是将用户缓存空间中的数据,写入了内核缓存,这时调用就返回成功了。而其实数据并没有立刻就写回磁盘。这样处理的原因,一方面有可能提高后续读取数据的处理效率,另一方面系统是为了提高写回文件时的处理效率,通过内核缓存一定的数据然后一次性写回,避免磁头的多次寻轨(参见缓冲I/O 即 Stdio)当然这就需要考虑同步的问题,而且何时写回文件也需要考虑其策略,一般会定义一个缓存在内核中的生命期。2.2.3 fsync / fdatasync这2个调用是为了确保内存中的脏数据与磁盘上的进行同步。前者不仅进行数据同步,还会同步文件的元数据。2.2.4 poll / selectl I/O多路复用的特点首先,我们监听多个描述符,当没有描述符准备好时,处于休眠状态;其次,一旦有描述符准备就绪,将唤醒,并根据事件类型进行处理;最后,返回第一步。l select 与 poll的优劣select比较传统,使用比较广泛(习惯、可移植性),麻烦的地方在于需要每次都设置描述符集(调用FD_x宏),计算最大描述符等。且select是对max_fd以下的所有描述符进行探测,当该值很大的时候,十分影响效率。poll因为将被监听的描述符集合与就绪的描述符集合进行了区分,因此不需要每次都进行设置。且每一个pollfd中负责一个对象,可以由用户来指定需要探测的描述符。但是poll移植性不佳。两者有共同的问题就是,系统都需要监听所有的描述符,当描述符列表很大的时候,这个行为将会十分影响效率。这个问题在epoll那里得到了很好的解决。2.3 基本I/O的特性,优劣首先我们要清楚的是,Unix的一个核心理念:everything is a file. 那么我们在需要进行I/O的时候,就自然有上面列出的各种操作:打开、定位、读、写、关闭以及获取文件信息等。但我们通过基本I/O的接口可以发现,这些调用都是直接与磁盘文件在打交道。我们知道,磁盘的读写与内存相比是慢了一个数量级以上的,如果频繁的进行这样的系统调用,那么系统的效率将势必十分低下。这就催生了缓冲I/O的出现,我们平时使用的标准c提供的stdio,即为一种应用广泛的缓冲I/O。3 标准c提供的缓冲I/O(即Stdio)3.1 缓冲 I/O 的原理关于缓冲I/O,很重要的一点,就是要搞清楚缓冲区是位于用户区的,而前面提到的基本I/O的缓冲区则属于内核。当调用进行缓冲读时,实际上的行为是首先调用read,从内核缓冲区将数据拷贝到用户缓冲区,再通过stdio的接口比如fgetc,将用户缓冲的数据拷贝到指定的缓存。缓冲写的过程则相反。3.2 常用函数l fopen / fdopen / fclose / fseek l fread / fgetc / fgetsl fwrite / fputc / fputsl 其他,包括 fflush / feof / fileno / flockfile / funlockfile 等3.3 主要接口关键特性及注意事项3.3.1 二进制读写 fread / fwrite这里需要注意的主要就是,因为变量的大小、字节序、填充、对齐等因素,通常一个程序写的二进制文件,只有该程序可以读取。不同程序、同一程序的不同版本(包括运行环境不同)都可能是不能读取的。3.3.2 fseek这个函数的功能和lseek一样,都是进行定位,但前者是对fd进行操作,后者是对fp进行操作。尤其要注意的是,fseek与lseek不应当混用,其结果是未定义的。3.3.3 fflush将所有流中的数据写入内核缓冲区。一般会和fsync连用,表明首先将用户缓冲区的内容冲入内核,然后将内核缓冲区的数据同步到磁盘。3.4 缓冲I/O是如何提升性能的首先,它有自己的用户缓冲区,将数据读入后,不再需要频繁的调用系统调用从内核缓冲区读写数据。这就降低了系统调用的开销。只有当必须与磁盘等介质交互时,才会进行系统调用。第二,通过设置缓冲区,以及设备块的大小,并且一次性读/写块大小的整数倍数据时,是在物理上更高效的,原因有2。其一,一次性读写相当的数据可以减少系统调用次数,其二,按照整块的方式来读写,性能更高。3.5 缓冲I/O的不足l 线程安全问题 l 部分函数不够安全,比如 getsl 数据的多次拷贝问题后者的问题,我们可以在高级I/O中找到更好的选择4 高级I/O4.1 散布/聚集 I/O readv / writev这里的v,是向量的意思,顾名思义,这类I/O实际上有点就在于,能够一次性的对与分散在多个不连续的缓冲区中的数据进行读写,减少了大量的系统调用。从另一方面来将,避免了若干个连续的线性I/O,也实现了I/O的原子性。4.2 更高级的多路复用 epoll能够逐个描述符的指定需要监听的事件,系统也将只监听被指定的描述符,大大提高了效率。4.3 存储映射 mmap / mummap这种方式,是直接将文件的某一段,按照页为单位映射进内存,然后透明的进行读写。优点有:读写映射文件,就像进行内存操作一样简单,不需要进行系统调用,也省略了多余的数据拷贝。缺点有:必须按照整页为单位进行映射,导致可能会出现许多大小不一的碎片。因此,处理较大文件、或大小为page size的整数倍的文件比较有优势。4.4 文件I/O提示通过提示内核将要对文件进行什么模式的I/O,内核将决定如何读取文件到内存,以此来在有限的内存的条件下,提高RAM的命中率,从而提高处理效率。主要的模式有:一般,顺序,随机等。对应的处理方式:少量预读,大量预读,不预读。5 其他需注意的问题5.1 关于I/O调度为什么需要调度?因为如果按照程序的顺序进行系统调用,那么几乎是无法避免的要进行大量的seek操作,这将导致磁头进行大量的寻道,从而导致效率低下。I/O调度器的功能就很显然了:将分布在多个I/O调用中的目标数据块进行排序,将临近的数据块一次性进行读写。即两个功能:合并、排序。5.2 优化读请求这里指的是内核从磁盘读取文件的算法,典型的有电梯算法,Dead-line算法等。重要性不言而喻。那么为什么强调优化读请求?一般而言,读请求需要返回最新的数据,如果无法命中RAM,那么读请求在数据从磁盘中返回前会一直阻塞。而写

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论