免费注册 查看新帖 |

Chinaunix

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

[C] 非阻塞read/write的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-01-15 22:01 |只看该作者 |倒序浏览
该程序是APUE2第14章程序清单14-1

  1. #include "head.h"

  2. char            buf[500000];

  3. int main(int argc, char** argv)
  4. {
  5.         int                     nwrite, ntowrite;
  6.         char                    *ptr = NULL;

  7.         ntowrite = read(STDIN_FILENO, buf, sizeof(buf));
  8.         fprintf(stderr, "read %d bytes\n", ntowrite);

  9.         set_fl(STDOUT_FILENO, O_NONBLOCK);
  10.         ptr = buf;
  11.         while(ntowrite > 0){
  12.                 errno = 0;
  13.                 nwrite = write(STDOUT_FILENO, ptr, ntowrite);
  14.                 fprintf(stderr, "nwrite = %d bytes, errno = %d\n", nwrite, errno);

  15.                 if(nwrite > 0){
  16.                         ntowrite -= nwrite;
  17.                         ptr += nwrite;
  18.                 }
  19.         }

  20.         clr_fl(STDOUT_FILENO, O_NONBLOCK);

  21.         exit(0);
  22. }

  23. static int set_fl(int fd, int flags)
  24. {
  25.         int             val;

  26.         val = fcntl(fd, F_GETFL, 0);
  27.         if(val < 0){
  28.                 perror("fcntl get error");
  29.                 exit(1);
  30.         }

  31.         val |= flags;
  32.         if(fcntl(fd, F_SETFL, val) < 0){
  33.                 perror("fcntl set error");
  34.                 exit(2);
  35.         }

  36.         return 0;
  37. }

  38. static int clr_fl(int fd, int flags)
  39. {
  40.         int             val;
  41.         
  42.         val = fcntl(fd, F_GETFL, 0);
  43.         if(val < 0){
  44.                 perror("fcntl get error");
  45.                 exit(3);
  46.         }

  47.         val &= ~flags;
  48.         if(fcntl(fd, F_SETFL, val) < 0){
  49.                 perror("fcntl clr error");
  50.                 exit(4);
  51.         }

  52.         return 0;
  53. }
复制代码

运行结果:
[xxxx@localhost chap14]$ ./a.out </etc/termcap >temp.file
read 500000 bytes
nwrite = 500000 bytes, errno = 0


[xxxx@localhost chap14]$ ./a.out </etc/termcap  2>stderr.out
[xxxx@localhost chap14]$ cat strerr.out
...............................
nwrite = -1 bytes, errno = 11
nwrite = -1 bytes, errno = 11
nwrite = -1 bytes, errno = 11
nwrite = -1 bytes, errno = 11
nwrite = -1 bytes, errno = 11
............................
nwrite = -1 bytes, errno = 11
nwrite = -1 bytes, errno = 11
nwrite = 109270 bytes, errno = 0

程序从标准输入中读取500000个字节的数据到进程缓冲区buf中,然后将标准输出设置为非阻塞模式,将buf缓冲区里的数据输出至标准输出
1.为什么当标准输出重定向到一个普通文件的时候,程序一次输出到文件成功,而当标准输出是终端时,为什么有write出现errno呢?
书中说:这个实例中,程序发出数千个write调用,但只有10-20个是真正输出数据的,其余的出错返回,这种形式的循环即轮询,在多
用户系统上它浪费CPU时间,这里“程序发出数千个write调用,但只有10-20个是真正输出数据的”不明白是怎么回事?

2. 书中说:虽然读写磁盘操作会使调用者短时间内阻塞,但不能将与磁盘操作有关的系统调用称为“低速”。
而低速系统调用是可能使进程永远阻塞的系统调用,read/write调用也可能使进程永远阻塞啊,难道read/write不是
低速系统调用吗?

论坛徽章:
0
2 [报告]
发表于 2008-01-15 23:10 |只看该作者
1.设置了O_NONBLOCK标志后,如果进程在缓冲区没有空间时(受终端驱动程序一次接收量的大小限制)调用了write,并不会阻塞,系统会立即返回EAGAIN :Resource temporarily unavailable

2.注意这句:不能将与磁盘操作有关的系统调用称为“低速”。
write终端会阻塞,但write文件(与磁盘操作有关)不会阻塞

个人理解,不知道对不对

论坛徽章:
0
3 [报告]
发表于 2008-01-15 23:41 |只看该作者
原帖由 xi2008wang 于 2008-1-15 23:10 发表
1.设置了O_NONBLOCK标志后,如果进程在缓冲区没有空间时(受终端驱动程序一次接收量的大小限制)调用了write,并不会阻塞,系统会立即返回EAGAIN :Resource temporarily unavailable

2.注意这句:不能将与磁盘操作 ...

对于1.觉得你的理解是对 的,这样说誓不是更好点:
当设置了O_NONBLOCK标志后,如果内核缓冲区(写队列)没有空间时(已经满了,守护进程updata还没来得及把写队列的数据冲洗到终端上)再次调用write往内核的写队列写数据时,并不会阻塞,系统立即返回EAGAIN
觉得你 所说的进程在缓冲区没有空间说的好像不对。:wink: :wink: :wink:

论坛徽章:
0
4 [报告]
发表于 2008-01-15 23:46 |只看该作者

回复 #2 xi2008wang 的帖子

write调用首先是把我们自己定义的缓冲区里的内容复制到内核缓冲区中,然后将内核缓冲区的内容放入写队列后write返回,系统的守护进程update会定期的调用sysn函数冲洗内核缓冲区写队列的内容.

论坛徽章:
0
5 [报告]
发表于 2008-01-15 23:54 |只看该作者

回复 #2 xi2008wang 的帖子

问题2还是不理解
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP