Linux系统编程读书笔记

文件I/O模型

Linux的哲学思想,一切皆文件,这也是Linux文件操作的方便之处。系统调用不会分配缓冲区用以返回信息给调用者。所以必须提前分配大小合适的缓冲区并将缓冲区指针传递给系统调用。

1、open

open以前没有创建功能,后来通过参数可以设置创建文件。一个进程对能够打开的文件描述符的个数有限制的。

open的时候如果指定O_SYNC标志,则会使所有后续输出同步。即调用write会自动都将文件数据和元数据刷新到磁盘。现代的磁盘驱动器均内置大型高速缓存,而默认情况下使用O_SYNC只是将数据传递到该缓存中。如果禁用磁盘上的高速缓存,那么O_SYNC标志堆IO性能影响挺大的。尽量不用O_SYNC。

2、read

read对于普通文件,一般都是用一个循环,一次读请求的字节数,只有读到普通文件末尾返回0,读取的字节数可能小于请求的;但是对于管道,FIFO,socket和终端,在不同环境下也会出现read调用读取的字节数小于请求字节数。默认情况下,从终端读取字符,一遇到换行符,read调用就会结束。

另外,read调用没有在末尾给你添加上一个‘\0’,所以需要显示添加。

3、write

write调用成功,将返回实际写入的文件字节数。

4、close显示

显示关闭不再需要的文件描述符是一个好的编程习惯。

文件I/O缓冲

出于速度和效率的考虑,系统调用I/O和标准C语言库I/O函数在操作磁盘文件的时候会对数据进行缓冲。

缓存cache是为了加快读,缓冲buffer是为了缓冲写

1、用户缓冲区大小对read和write系统调用I/O性能的影响

前文说的read和write系统调用,这里在说一下。write只是将用户空间缓冲区中的内容复制到内核高速缓存中,做完这些write调用就结束了。在后续某个时刻,内核会将其高速缓存的数据写入(刷新至)磁盘。因此,可以说系统调用和磁盘操作并不同步。如果还没有刷新到磁盘的时候,有进程需要读取这个文件的这几个字节,那么内核会自动从高速缓存提供这些数据,而不是从文件。与此同理,read系统调用只是将内核高速缓存的数据复制到用户空间的缓冲区,内核高速缓存数据被取完之后,内核会将文件的下一段内容读取到内核高速缓存中。采用这中设计,一是read和write系统调用的操作更为迅速,二是减少了内核必须执行的磁盘传输操作

内存高速缓冲区在Linux中设计为页面大小,所以,当用户空间缓冲区的大小大于等于页面大小的时候效率比较高。Linux内核尽可能多的分配高速缓存页。当内存空间紧张的时候,会对一些修改过的缓存页进行刷新并释放空间。

2、stdio库的缓冲

C语言函数库的I/O函数(比如    fprintf()/fscanf()    fputs()/fgets()    fputc()/fgetc())缓冲大块数据减少系统调用。

我们可以调用setvbuf来设置stdio的缓冲模式。

(1)_IONBF   不对I/O进行缓冲  对每个库函数立即调用读写系统调用

(2)_IOLBF    采用行缓冲I/O    只要有一行或者满了执行读写系统调用

(3)_IOFBF    采用全缓冲I/O    缓冲区满了才执行读写系统调用

设置不同的模式,read和write的调用时机是不一样的。不缓冲——调用库函数往缓冲区里放入数据,放入后立马write到内核的高速缓存区。行缓冲——调用库函数往缓冲区中放入数据,只要数据中含有换行符或者缓冲区满了,就会write到内核的高速缓存区。全缓冲——调用库函数往缓冲区中放入数据,只有满了的时候才会调用write系统调用将数据写入内核高速缓存区。读的时候同理。

3、I/O缓冲小结

 I/O系统调用其实就是将缓冲区的内容与内核高速缓存区进行复制,没有缓冲模式。但是stdio库函数会根据缓冲模式进行复制。

posted @ 2016-11-07 19:40  苏羽垄  阅读(903)  评论(0编辑  收藏  举报