select函数与stdio混用的不良后果 (转)
出自:http://www.cppblog.com/mysileng/archive/2013/01/15/197284.html
今天在看UNP6.5节,学习到了select与stdio混用的后果。特此进程实验一番。再实验之前需明确一下几点:
1.stdio流的i/o函数 与 系统i/o函数不同。stdio流函数在用户空间和内核都有缓冲,系统i/o函数只在内核有缓冲,用户空间没有。
2.stdio流的i/o函数缓冲机制:在面对文件时候用的是全缓冲,面对设备的时候用的行缓冲。(等下试验用的是键盘和屏幕),所以实验用的stdio函数采用行行缓冲。
3.select函数对于某一个描述符是否准备好可读可写,是对内核缓冲区中的数据是否达到某一个最低标准,而不是用户缓冲区。也就是说select函数不知道用户缓冲区的存在。
首先写了一个系统i/o函数 简单的select函数程序:
程序给select函数只设置的键盘的描述符。也就是说如果键盘的描述符准备好了就不再阻塞。但是这里有一个问题,解除阻塞后,我们最多只从内核缓冲区读3个字节,这个时候就会有两个情况:
(1)内核空间本来存储的数据就小于等于3个字节,全被读走。那下次再次调用select函数,应该肯定会阻塞的,因为键盘输入的内核缓冲区已经没有数据了。
情况如下(内核空间只有3个字节:1 2 \n):
(2)如果内核空间的数据多余3个字节,但是因为最多只能读3个字节,就必将导致内核中有数据读不完。那么下次再遇到select函数的时候是否会阻塞呢?
情况见下:
当我们输入5个字符时候(1 2 3 4 \n),第一次read掉3个字符,内核空间还剩下2个字符,然后再次碰到select函数,默认情况下如果键盘内核空间字符数大于1,select是不会阻塞键盘描述符的。结果也印证了,又read了2个字节,并没有堵塞。
综上所述select是可以看见内核空间的缓冲区的。那到底能不能看见用户空间缓冲区呢?我们换成stdio流的i/o函数继续实验。
--------------------------------------------------------------------
stdio流的i/o函数使用select函数的程序如下:
程序用stdio流的getc函数从键盘读数据,运行结果如下:
我们输入5个字符(1 2 3 4 \n),结果只输出了1个字符,然后就阻塞了。我们分析一下,首先输入5个字符,这5个字符被放入用户缓冲区,因为最后一个是换行符并且stdio面对设备使用行缓冲机制,所以这5个字符马上接着被从用户缓冲区刷入内核缓冲区。然后调用select函数,select函数发现内核空间中有数据,于是不阻塞返回。接着getc函数从用户空间输出缓冲区取一个字符,因为用户空间输出缓冲区没有数据,于是把内核空间的数据调入一行给用户空间输出缓冲区,然后getc返回。接着又碰上select函数,因为内核缓冲空间的数据已经被放入用户空间输出缓冲区了,所以内核缓冲没有数据,那么select认为键盘没有准备好,所以阻塞。虽然阻塞了,但需要注意的时候这个时候,用户空间是有4个字符数据的,被select函数无视了。
接下来假设我们再输入2个字符(1 \n),将会发生什么呢?
输出一对东西,这是怎么回事,我们继续分析。当输入2个字符(1 \n)的时候,内核空间缓冲没有数据,用户空间输出缓冲有4个字符。2个字符根据上一段同样原理,被刷入内核空间缓冲区。select函数被调用,发现有2个字符,于是不阻塞返回。getc函数从用户输出缓冲取出一个字符,打印stardard... --2然后返回。再次循环,调用select函数。关键来了,这里跟上次不一样了。这个时候内核空间的缓冲中还有上次遗留的2个字符,所以依然不阻塞返回,调用getc函数继续打印。。。这里的关键是,getc函数。getc函数在用户输出缓冲中有数据的时候,不会把内核空间缓冲中的数据移入用户空间的输出缓冲,使得内核空间缓冲一直留有数据。这将会持续到用户空间输出缓冲的数据被取完为止。所以上述奇怪的打印结果就可以解释的了。
综上所述,select函数确实是看不见用户空间缓冲的寻在的。
所以如果在使用select函数的时候,要谨慎使用stdio流函数。
select函数与stdio混用的不良后果 (转)的更多相关文章
- select与stdio混合使用的不良后果
参考以下链接自己补充实验:http://www.cppblog.com/mysileng/archive/2013/01/15/197284.aspx?opt=admin int main(int a ...
- select函数实例代码
select函数简解: selct 称之为多路复用IO,使用它可以让程序阻塞在select上,而非实际IO函数上. int select(int nfds, fd_set *readfds, fd_s ...
- select 函数1
Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect.accept.recv或recvfrom这样的阻塞程序( ...
- IO复用与select函数
socket select函数的详细讲解 select函数详细用法解析 http://blog.chinaunix.net/uid-21411227-id-1826874.html linu ...
- 异步套接字基础:select函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
参考:[原创]技术系列之 网络模型(三)多路复用模型 select函数 select函数: 系统提供select函数来实现多路复用输入/输出模型.原型: #include <sys/time.h ...
- Linux下select函数的使用
一.Select 函数详细介绍 Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect. accept.recv ...
- linux c语言 select函数用法
linux c语言 select函数用法 表头文件 #i nclude<sys/time.h> #i nclude<sys/types.h> #i nclude<unis ...
- select函数的介绍和使用
我们所使用的I/O模型一共有五种. 分别为阻塞I/O,非阻塞I/O,I/O复用,信号驱动I/O,异步I/O. 所谓I/O复用就是指管理多个I/O文件描述符,一般会使用(select,poll,epol ...
- UNIX网络编程——select函数的并发限制和 poll 函数应用举例
一.用select实现的并发服务器,能达到的并发数,受两方面限制 1.一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n来调整或者使用setrlimit函数设置, ...
随机推荐
- win8/10 bcdboot引导修复命令的原理和使用方法
win8/10 bcdboot引导修复命令的原理和使用方法 [迅维网原创文章禁止转载] (本文所述已用UEFI+GPT.BIOS+MBR,WIN10 64位企业版和专业版测试过) 在win8/10系统 ...
- stack与heap、new的内存分配、static对象。(effective c++ 04)
阅读effective c++ 04 (30页) 提到的static对象和堆与栈对象."不同编译单元内定义的non-local static对象". 了解一下. 目录 sta ...
- [bzoj]1930 pacman吃豆豆
Description 两个PACMAN吃豆豆.一开始的时候,PACMAN都在坐标原点的左下方,豆豆都在右上方.PACMAN走到豆豆处就会吃掉它.PACMAN行走的路线很奇怪,只能向右走或者向上走,他 ...
- pandas实践——美国人口分析
1.导入文件,并查看数据样本 abbr = pd.read_csv("./state-abbrevs.csv")areas =pd.read_csv("./state-a ...
- python--字符编码理解
一.字符编码简史: 美国:1963年 ASCII (包含127个字符 占1个字节) 中国:1980年 GB2312 (收录7445个汉字,包括6763个汉字和682个其它符号) 1993年 GB13 ...
- MongoDB之Replica Sets环境搭建
最近学习MongoDB,这两天在搭建复制集的时候碰到了不少问题,也踩了好多坑,现在在这里记录下来,以供自己和他人参考 (因为本人是初学者,所以遇到的问题也会比较初级,所以本文也比较适合初学者查阅) 背 ...
- stm32之Cortex系统定时器(SysTick)
转载自:http://www.21ic.com/app/mcu/201811/781135.htm SysTick时钟,俗称“嘀嗒定时器”,它能按设定的时间产生一次中断.控制工程代码中随处可见形如 ...
- Hard problem CodeForces - 706C
Time limit1000 ms Memory limit262144 kB 题目: Vasiliy is fond of solving different tasks. Today he fou ...
- debian右键添加在终端中打开
sudo apt-get install nautilus-open-terminal -y 注销,重启
- BZOJ 5334: [Tjoi2018]数学计算
线段树裸题 难度在于认识到这个没法线性做 #include<cstdio> using namespace std; int n,mod,tr[400005]; void insert(i ...