博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux 标准IO缓冲机制探究
阅读量:4294 次
发布时间:2019-05-27

本文共 3860 字,大约阅读时间需要 12 分钟。

一、什么是缓存I/O(Buffered I/O)
缓存I/O又被称作标准I/O,大多数文件系统默认I/O操作都是缓存I/O。在Linux的缓存I/O机制中,操作系统会将I/O的数据缓存在文件系统的页缓存(page cache)中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。
1.缓存I/O有以下优点:
A.缓存I/O使用了操作系统内核缓冲区,在一定程度上分离了应用程序空间和实际的物理设备。
B.缓存I/O可以减少读盘的次数,从而提高性能
        当应用程序尝试读取某块数据的时候,如果这块数据已经存放在页缓存中,那么这块数据就可以立即返回给应用程序,而不需要经过实际的物理读盘操作。当然,如果数据在应用程序读取之前并未被存放在页缓存中,那么就需要先将数据从磁盘读到页缓存中去。对于写操作来说,应用程序也会将数据先写到页缓存中去,数据是否被立即写到磁盘上去取决于应用程序所采用的写操作机制:如果用户采用的是同步写机制,那么数据会立即被写回到磁盘上,应用程序会一直等到数据被写完为止;如果用户采用的是延迟写机制,那么应用程序就完全不需要等到数据全部被 写回到磁盘,数据只要被写到页缓存中去就可以了。在延迟写机制的情况下,操作系统会定期地将放在页缓存中的数据刷到磁盘上。与异步写机制不同的是,延迟写机制在数据完全写到磁盘上得时候不会通知应用程序,而异步写机制在数据完全写到磁盘上得时候是会返回给应用程序的。所以延迟写机制本省是存在数据丢失的风险的,而异步写机制则不会有这方面的担心。
2.缓存I/O的缺点
        
        在缓存I/O机制中,DMA方式可以将数据直接从磁盘读到页缓存中,或者将数据从页缓存直接写回到磁盘上,而不能直接在应用程序地址空间和磁盘之间进行数据传输,这样的话,数据在传输过程中需要在应用程序地址空间和页缓存之间进行多次数据拷贝操作,这些数据拷贝操作说带来的cpu以及内存开销是非常大的。
二、文件指针
FILE指针:每个被使用的文件都在内存中开辟一个区域,用来存放文件的有关信息,这些信息是保存在一个结构体类型的变量中,该结构体类型是由系统定义的,取名为FILE。
标准I/O库的所有操作都是围绕流(stream)来进行的,在标准I/O中,流用FILE *来描叙的。
其在Linux操作系统中的定义:
三、行缓冲、全缓冲、不缓冲的定义
1.Fully buffered means that I/O takes place only when the buffer is fully, the process explicitly calls fflush, or the process terminates by calling exit. A common size for the standard I/O buffer is 4096 bytes;
2. Line buffered means that I/O takes place when a newline is encountered, when the process calls fflush, or when the process terminates by calling exit.
3. Unbuffered means that I/O take place each time a standard I/O output function is called.
Most unix implementations of the standard I/O libarary use the following rules.
1. Standard error is always unbuffered.
2. Standard input and standard output are fully buffered, unless they refer to a terminal device, in which case, they are line buffered.
3. All other streams are fully buffered unless they refer to a terminal device,
in which case, they are line buffered.
四、一步步探究
  1. #include <stdio.h>
  2. int stream_attribute(FILE *fp)
  3. {
  4. if(fp->_flags & _IO_UNBUFFERED)
  5. {
  6. printf("The IO type is unbuffered\n");
  7. }else if(fp->_flags & _IO_LINE_BUF){
  8. printf("The IO type is line buf\n");
  9. }else{
  10. printf("The IO type is full buf\n");
  11. }
  12. printf("The IO size : %d\n",fp->_IO_buf_end - fp->_IO_buf_base);
  13. return 0;
  14. }
  15. int main()
  16. {
  17. FILE *fp;
  18. stream_attribute(stdin);
  19. printf("___________________________________\n\n");
  20. stream_attribute(stdout);
  21. printf("___________________________________\n\n");
  22. stream_attribute(stderr);
  23. printf("___________________________________\n\n");
  24. if((fp = fopen("test.txt","w+")) == NULL)
  25. {
  26. perror("fail to fopen");
  27. }
  28. stream_attribute(fp);
  29. return 0;
  30. }
运行结果:
我们修改一下代码再看
  1. #include <stdio.h>
  2. int stream_attribute(FILE *fp)
  3. {
  4. if(fp->_flags & _IO_UNBUFFERED)
  5. {
  6. printf("The IO type is unbuffered\n");
  7. }else if(fp->_flags & _IO_LINE_BUF){
  8. printf("The IO type is line buf\n");
  9. }else{
  10. printf("The IO type is full buf\n");
  11. }
  12. printf("The IO size : %d\n",fp->_IO_buf_end - fp->_IO_buf_base);
  13. return 0;
  14. }
  15. int main()
  16. {
  17. FILE *fp;
  18. getchar();
  19. stream_attribute(stdin);
  20. printf("___________________________________\n\n");
  21. stream_attribute(stdout);
  22. printf("___________________________________\n\n");
  23. stream_attribute(stderr);
  24. printf("___________________________________\n\n");
  25. if((fp = fopen("test.txt","w+")) == NULL)
  26. {
  27. perror("fail to fopen");
  28. }
  29. printf("before write:\n");
  30. stream_attribute(fp);
  31. fputc('a',fp);
  32. printf("after write:\n");
  33. stream_attribute(fp);
  34. return 0;
  35. }
运行结果:
从以上我们可以看出,标准I/O并不是一开始就分配的,只有进行了输入或者输出的操作才进行分配的,标准输入和标准输出默认是全缓冲,但是如果和终端关了就是行缓冲。可以看到在linux操作系统中行缓冲的大小是1k,全缓冲的大小是4k。
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(31) | 评论(0) | 转发(0) |
0

上一篇:

下一篇:

相关热门文章
给主人留下些什么吧!~~
评论热议

转载地址:http://osuws.baihongyu.com/

你可能感兴趣的文章
Overlay之VXLAN架构
查看>>
Eclipse : An error occurred while filtering resources(Maven错误提示)
查看>>
在eclipse上用tomcat部署项目404解决方案
查看>>
web.xml 配置中classpath: 与classpath*:的区别
查看>>
suse如何修改ssh端口为2222?
查看>>
详细理解“>/dev/null 2>&1”
查看>>
suse如何创建定时任务?
查看>>
suse搭建ftp服务器方法
查看>>
centos虚拟机设置共享文件夹并通过我的电脑访问[增加smbd端口修改]
查看>>
数据库创建索引有什么优点和缺点
查看>>
mysql创建各类索引的方法
查看>>
【好文讲的很清晰】复合索引
查看>>
awk将文本转置(行转列)-以及if判断
查看>>
linux-awk中NF与$NF的区别
查看>>
VScode结合anaconda 进行pip包安装
查看>>
win7 系统更新的临时文件删除
查看>>
windows批量杀进程
查看>>
Excel快捷键:全选指定行以下的所有内容&两表同字段数据合并&查找两列相同数据
查看>>
CSS使用通配符作为选择器
查看>>
puppeteer 爬虫入门教程
查看>>