免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4392 | 回复: 16
打印 上一主题 下一主题

再问缓冲区问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-10-09 09:21 |只看该作者 |倒序浏览
在另一个版面发过帖子但是回复的不多,有人建议到这里来问问。

最近遇到了缓冲区方面的问题,请各位帮忙解决一下。
以下几个说法对吗?
1、c库函数有一个内核缓冲区,一个用户缓冲区;系统调用只有一个内核缓冲区。
2、新建一个进程,系统会自动分配一个缓冲区给它。
3、进程中各个打开的文件,每个文件描述符具有自己的缓冲区(是这样吗?还是共用进程的内核缓冲区?还是以文件为单位创建内核缓冲?)
   fd读写方式打开一个文件,(用read,write)先写后读,写是写到内核缓冲,后读读的是不是也是内核缓冲区里面的内容?还是磁盘文件里面的(仿佛此时还没刷新缓冲到磁盘)。
   fd1、fd2分别打开两个不同的文件,写fd1,紧接着读fd2,会把刚写入内核缓冲的东西读出来吗?

晕晕的,仙人请指路!

论坛徽章:
0
2 [报告]
发表于 2007-10-09 10:33 |只看该作者
1. 正确
2. 新建一个进程, 就是不同的地址空间了. 每个进程都有其4G的地址空间. 你这个缓冲区是什么意思?
3. 每个文件描述符当然有其自己的缓冲区. 当然不会把刚刚写入的内容读出来. 你自己编个程序试试不就知道了吗?
你这几道题只要自己编下程就知道了. APUE3, 5章有详细的讲解.
还有, 在对应用程序不太熟悉之前不要动不动就说内核什么的.

论坛徽章:
0
3 [报告]
发表于 2007-10-09 12:45 |只看该作者
这两个例子分别是(1)两次打开同一个文件(2)两次打开两个文件 的例子,我编程做过,对于结果不太肯定,我是一名教师,正好即将要讲到这个知识点,为了给学生一个明确的说法,想找高手答疑解难。
write和read都是与内核缓冲区打交道,不是直接和磁盘文件打交道。
(1)读fd2会把刚写入fd1的内容读出来,好像fd1和fd2共享一个缓冲区
(2)读fd2不能读出刚写入fd1的内容,fd1和fd2不是共享一个缓冲区

另外还有一个问题:write(1,buf4,n)中第一个参数我写成(0 1 2)都是正确显示buf4中的内容,为什么?
谢谢!
第一个例子
#include <unistd.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdio.h>

int main()
{
   int n;
   int fd1,fd2;
   char buf1[10]={"1234567890"};
   char buf2[10]={"abcdefghij"};
char buf4[5];
   if ( ( fd1 = open( "file1.txt",O_RDWR| O_CREAT | O_TRUNC, S_IRUSR |S_IWUSR))
==-1 )
        perror("file1.txt open error");
   printf("the fd1 = %d \n",fd1);                       //

   if ( ( fd2 = open( "file1.txt", O_RDWR)) == -1 )
       perror("file1.txt not open again " );
   printf("the fd2 = %d \n",fd2);

   if (( n = write(fd1,buf1,sizeof(buf1))) == -1)
        perror("write file1.txt error");
    printf("write %d char into fd1 \n",n);

   if ((n = read(fd2,buf4,sizeof(buf4))) == -1 )
        perror("read file1.txt error! ");
    printf("read %d char from fd2 \n",n);
   write(1,buf4,n);
   printf("\n");


   close(fd1);
   close(fd2);
}

第二个例子
#include <unistd.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdio.h>

int main()
{
   int n;
   int fd1,fd2;
   char buf1[10]={"1234567890"};
   char buf2[10]={"abcdefghij"};
char buf4[5];
   if ( ( fd1 = open( "file1.txt",O_RDWR| O_CREAT | O_TRUNC, S_IRUSR |S_IWUSR))==-1 )
        perror("file1.txt open error");
   printf("the fd1 = %d \n",fd1);                       //

   if ( ( fd2 = open( "file2.txt",O_RDWR| O_CREAT | O_TRUNC, S_IRUSR |S_IWUSR))==-1 )
       perror("file1.txt not open again " );
   printf("the fd2 = %d \n",fd2);

   if (( n = write(fd1,buf1,sizeof(buf1))) == -1)
        perror("write file1.txt error");
    printf("write %d char into fd1 \n",n);

   if ((n = read(fd2,buf4,sizeof(buf4))) == -1 )
        perror("read file1.txt error! ");
    printf("read %d char from fd2 \n",n);
   write(1,buf4,n);
   printf("\n");


   close(fd1);
   close(fd2);
}

论坛徽章:
0
4 [报告]
发表于 2007-10-09 13:10 |只看该作者
1. 你写入与读出的都是同一个文件, 那么你读出来的当然就是你写进去的内容哦. 这和缓冲区没关系. 你另外弄个文件, file2.txt 然后fd2打开这个文件, 看读出来的内容又是什么呢?
2. 一般情况下1是标准输出, 2是错误输出, 0是标准输入, 都是与屏幕相关联的, 只要不对其进行重定向, 那么就是向屏幕进行输出.
3. 你的程序中有很多潜在的危险. 比如 char buf1[10]={"1234567890"};

论坛徽章:
0
5 [报告]
发表于 2007-10-09 14:13 |只看该作者
建议楼主看一下内核源码下的include/linux/fs.h里关于file结构的定义,它就是文件描述符,里面有个字段是文件偏移量

论坛徽章:
0
6 [报告]
发表于 2007-10-09 17:14 |只看该作者
1. 你写入与读出的都是同一个文件, 那么你读出来的当然就是你写进去的内容哦. 这和缓冲区没关系. 你另外弄个文件, file2.txt 然后fd2打开这个文件, 看读出来的内容又是什么呢?

不是write的时候不是直接写入磁盘而是在缓冲区中吗?

2. 一般情况下1是标准输出, 2是错误输出, 0是标准输入, 都是与屏幕相关联的, 只要不对其进行重定向, 那么就是向屏幕进行输出.

为什么0是标准输入还能输出到屏幕上呢?

3. 你的程序中有很多潜在的危险. 比如 char buf1[10]={"1234567890"};

谢谢!比较匆忙,所以没有仔细检查。

论坛徽章:
0
7 [报告]
发表于 2007-10-09 17:27 |只看该作者
1.我想你说的这个缓冲区应该是指标准IO这个缓冲区吧, write()是系统调用, 它就直接陷入内核了, 然后将数据从用户态拷贝到内核态, 再通过VFS层, 块设备驱动层将数据写到文件所对应的磁盘上记录块上去, 当然, 在VFS, 块设备驱动层也是有缓冲区的, 但是这是由内核来控制的. 决定哪个时候将数据写到记录块上去.
而你说的那个方式应该是指fprintf()的时候, 这个时候是写到标准IO的缓冲区中去, 需要fflush()才能够写到具体的文件记录块中去.
你看看下面几个程序:

  1. #include<unistd.h>
  2. #include<stdio.h>

  3. int main()
  4. {
  5.         printf("hello");
  6.         fflush(stdout);
  7.         fork();
  8.         return 0;
  9. }


  10. #include<unistd.h>
  11. #include<stdio.h>

  12. int main()
  13. {
  14.         printf("hello");
  15.         fork();
  16.         return 0;
  17. }


  18. #include<unistd.h>
  19. #include<stdio.h>

  20. int main()
  21. {

  22.        write(1, "hello", 5);
  23.         fork();
  24.         return 0;
  25. }

复制代码

注意其中对hello的输出, 而标准输出是行缓存的形式, 所以后面的\n是将数据真正输出的一个标志.
2. 0虽然是标准输入, 但是其在内核中是与屏幕相关联的. 你往里面写, 当然会显示出来了. 它也是相当于是一个文件.

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
8 [报告]
发表于 2007-10-09 19:49 |只看该作者
原帖由 wkathy 于 2007-10-9 09:21 发表
在另一个版面发过帖子但是回复的不多,有人建议到这里来问问。

最近遇到了缓冲区方面的问题,请各位帮忙解决一下。
以下几个说法对吗?
1、c库函数有一个内核缓冲区,一个用户缓冲区;系统调用只有一个内核 ...

建议先安心看点书, 例如 APUE2 和 Linux Kernel Development(2nd) 就不错.

论坛徽章:
0
9 [报告]
发表于 2007-10-09 21:24 |只看该作者
建议先安心看点书, 例如 APUE2 和 Linux Kernel Development(2nd) 就不错.


谢谢!我曾试过看一些稍微深一点的书,但是总是看不明白怎么回事,所以在平时一遇到稍微底层一点的就糊涂了。

论坛徽章:
0
10 [报告]
发表于 2007-10-09 21:26 |只看该作者
建议楼主看一下内核源码下的include/linux/fs.h里关于file结构的定义,它就是文件描述符,里面有个字段是文件偏移量


谢谢!看过这个结构,但我还是没明白缓冲方面的问题。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP