对缓冲区的理解


这个是我今天自己写的对缓冲区的个人理解,仅是个人之间,仅供参考!
                                                      缓冲区的个人理解
这里所说的缓冲区指的是为标准输入与标准输出设置的缓冲区,为什么要设置一个标准输入缓冲区主要是从效率上来考虑的,如果不设缓冲区会降低cpu的效率,因为它总是会等待用户输入完之后才会去执行某些指令!同样设置一个标准输出缓冲区是为了解决打印的问题!总之这样做的目的就是为了效率!
接下来讲解一下怎么设置标准输入与标准输出缓冲区。
如果我们不认为的设置的话,系统会自动的为标准输入与标准输入设置一个缓冲区,这个缓冲区的大小通常是4Kb的大小,这和计算机中的分页机制有关,因为进程在计算机中分配内存使用的就是分页与分段的机制,并且每个页的大小是4Kb,因此通常情况下缓冲区的大小会设置为4Kb的大小!并且这个缓冲区的类型是一个全缓冲的缓冲区!所谓全缓冲指的是:当缓冲区里的数据写满的时候(或者可以说达到顶端)缓冲区中的数据才会“写”到标准输入磁盘文件中,这里说的写不是将缓冲区中的数据移动到磁盘文件中,而是拷贝到磁盘文件中,也就说此时磁盘文件中保留了一份缓冲区内容的备份!除了全缓冲外还有不缓冲和行缓冲,不缓冲不太常见与常用,在这里我就不做讲解了!下面讲解一下什么是行缓冲。行缓冲指的是当在键盘上敲下回车键的时候数据会存储在缓冲区中,这是毫无疑问的,同时也将缓冲区的数据拷贝一份到磁盘文件中!那么磁盘文件中备份的内容有什么用呢??本人能力有限目前还没有发现有什么用!
当热我们还可以自己设置缓冲区,缓冲区的大小可以由我们自己决定,缓冲区的类型也由我们自己决定!在这里有两个函数,一个是setbuf(   FILE *stream  ,  char *buffer  ) 另一个是setvbuf( FILE *stream  ,   char *buffer  ,  int mode  ,   unsigned int  size  ) ;
其中缓冲区的类型可以是:_IOFBF :全缓冲   _IOLBF :行缓冲  _IONBF : 不缓冲
下面讲解一下缓冲区是怎么工作的!
当我们从键盘输入数据的时候数据并不是直接被我们得到(这个问题我在上面已经讲解过了,不在重复),而是将这些输入的数据放在了缓冲区中,然后我们从缓冲区中得到我们想要的数据 !如果我们通过函数(setbuf , setvbuf)将缓冲区设置10个字节的大小,而我们从键盘输入了20个字节大小的数据,这样我们输入的前10个数据会放在缓冲区中,因为我们设置的缓冲区的大小只能够装下10个字节大小的数据,装不下20个字节大小的数据。那么剩下的那10个字节大小的数据怎么办呢??暂时放在了输入流中!如果不能够理解这个,那我举一个比较形象的例子:
(图片在我发的附件中)
上面的箭头表示的区域就相当是一个输入流,红色的地方相当于一个开关,这个开关可以控制往深绿色区域(标注的是缓冲区)里放进去的数据,输入20个字节的数据只往缓冲区中放进去了10个字节,剩下的10个字节的数据就被停留在了输入流里!等待下去往缓冲区中放入!接下来系统是如何来控制这个缓冲区呢?

在C语言方式下  是一个结构体数组  类型是FILE结构体
struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
结构体中的成员简单的介绍下
_ptr     //指向当前缓冲区内容的指针
_cnt     //如果是输入缓冲区  那他就是显示现在缓冲区里还有多少个有效数据
_base    //缓冲区基地址
_flag    //标志位   具体好像就是什么可写啊 可读啊之类的
_file    //这个是设备句柄(也可以说是文件句柄)
_bufsiz  //缓冲区总大小   一般都是0x1000    也就是4k   也就是一个分页

在上面我们向缓冲区中放入了10个字节大小的数据,FILE结构体中的_cnt变为了10 ,说明此时缓冲区中有10个字节大小的数据可以读,同时我们假设缓冲区的基地址也就是_base0x00428e60 ,它是不变的 ,而此时_ptr的值也为0x00428e60 ,表示从0x00428e60这个位置开始读取数据,当我们从缓冲区中读取5个数据的时候,_cnt变为了5 ,表示缓冲区中还有5个数据可以读,_ptr则变为了0x00428e65表示下次应该从这个位置开始读取缓冲区中的数据 ,如果接下来我们再读取5个数据的时候,_cnt则变为了0 ,表示缓冲区中已经没有任何数据了,_ptr变为了0x00428e69表示下次应该从这个位置开始从缓冲区中读取数据,但是此时缓冲区中已经没有任何数据了,所以要将输入流中的剩下的那10个数据放进来,这样缓冲区中又有了10个数据,此时_cnt变为了10 ,注意了刚才我们讲到_ptr的值是0x00428e69 ,而当缓冲区中重新放进来数据的时候这个_ptr的值变为了0x00428e60 ,这是因为当缓冲区中没有任何数据的时候要将_ptr这个值进行一下刷新,使其指向缓冲区的基地址也就是0x00428e60这个值!因为下次要从这个位置开始读取数据!

在这里有点需要说明:当我们从键盘输入字符串的时候需要敲一下回车键才能够将这个字符串送入到缓冲区中,那么敲入的这个回车键(\r)会被转换为一个换行符\n,这个换行符\n也会被存储在缓冲区中并且被当成一个字符来计算!比如我们在键盘上敲下了123456这个字符串,然后敲一下回车键(\r)将这个字符串送入了缓冲区中,那么此时缓冲区中的字节个数是7 ,而不是6。
缓冲区的刷新就是将指针_ptr变为缓冲区的基地址 ,同时_cnt的值变为0 ,因为缓冲区刷新后里面是没有数据的!
展开阅读全文

串口缓冲区的疑问

05-29

我用MScomm编写一个串口程序,之前遇到了许多问题,已经在这里发帖问过大家了,不过现在还是有问题,恐怕还要继续发帖求救,呵呵rn 我的任务是从一个下位机里接收数据,在PC机里面用VC6做一个基本的对话框,在里面将从下位机里收到的数据显示出来,这些数据包括探头电压,测量厚度,设备状态;还要通过对话框把一些控制信息发送到下位机,这些要发送的数据有设定时间,设定厚度。rn现在有几个问题我解决不了:rn 1:我用一个编辑框显示从串口读到的数据,这些数据按说只有个别位变化,即12**56**90,只有*号表示的位是变化的。但是接收到的数据是“滚动的”,比如这一刻是123456789,下一刻就是345678912,在下一刻就是567891234;这是为什么呢?该怎样解决?rn 2:发送与接收冲突。我希望在数据的接收的同时能够向下位机发送数据,但是但我发送的时候,发现显示接收的编辑框里面会多出几个数字:456***789,是不是串口发送与接收不能同时造成的?该怎样修改才能让接收的编辑框不受发送的影响?加延迟?rn 3:从下位机里发送的数据有AB两路,这两路是完全一样的。因为探头电压有正负之分,所以为正时发送5位数据,为负时多发送一位---负号。因此总的数据有时是40位,有时是42位(每一路发送的数据是20位或者21位),其中3~6位是测量厚度,8~10位是设备状态,11~15位是探头电压(如果电压为负则是11~16位)。现在都问题是使用什么函数来取得这些数据?我用的是测量厚度A:m_strShow.mid(3,4);设备状态A:m_strShow.mid(8,3);探头电压A:m_strShow.mid(11,6);测量厚度B:m_strShow.mid(24,4);设备状态B:m_strShow.mid(29,3);探头电压B:m_strShow.mid(32,6);不过当电压出现正负变化时,B路的读取就出现问题了:因为在A路有一个正负位的变化,因此A路发送的数据就会有20位或21位的变化,这样mid()函数中第一个参数就不容易确定了。有没有一个好的函数来解决这个问题?我觉得mid()函数用着不太方便,哪位网友能帮我想出一个好一点点的代码?rn 把我的代码的主要部分写出来:rn串口初始化部分:rn m_Com.SetSettings(m_strSetting);rn m_Com.SetRThreshold(42);rn m_Com.SetInputMode(1);rn m_Com.SetInputLen(42);rn串口响应函数:rnvoid CMyCommDlg::OnOnCommCommtral() rnrn // TODO: Add your control notification handler code herern COleVariant myVar;rn COleSafeArray SafeArray_inp;rn LONG len,k;rn BYTE rxdata[BUFSIZE+2];rn CString tempThick;rn float tFthick;rnrnrn if (bReceive)rn rn if (m_Com.GetCommEvent()==2)rn rn myVar=m_Com.GetInput();rn SafeArray_inp=myVar;rn len=SafeArray_inp.GetOneDimSize();rnrn for (k=0;k 论坛

有关缓冲区的问题

07-31

二个API:rnBOOL WINAPI ReadFile(rn __in HANDLE hFile,rn __out LPVOID lpBuffer,rn __in DWORD nNumberOfBytesToRead,rn __out_opt LPDWORD lpNumberOfBytesRead,rn __inout_opt LPOVERLAPPED lpOverlappedrn);rnrnBOOL WINAPI WriteFile(rn __in HANDLE hFile,rn __in LPCVOID lpBuffer,rn __in DWORD nNumberOfBytesToWrite,rn __out_opt LPDWORD lpNumberOfBytesWritten,rn __inout_opt LPOVERLAPPED lpOverlappedrn);rn rn第二参数:lpBuffer 这个缓冲区大小的设定有何意义对程序的性能是否有影响?rnrn1、10、50、256、1024、2048、102400000........有什么区别?rnrn其实这个问题是一个国外的论坛有人提出的,我当时的回答是:缓冲区大小的设定你不要考虑操作系统对硬的操作性能上有何影响,而重点考虑是否对你写的代码本身是否有影响。比如说你的代码一次只处理1024的数据,那就一次只读出1024的数据好了,为什么要读出2048的数据作2次循环处理呢?结果和一个外国人争论起来,从晚上九点争论到零晨3点,最后竟然以投票方式来决定对错。结果我输了321:412。我实在很难相信windows对硬件的操作这么简单,你要1024的数据我就从硬盘里读出1024的数据给你,我觉的windows早已从文件里读好了数据放在内存中等着你去调用了,当CreateFile的时候。但这种处理机制到底是什么样的,微软是不会让世人知道的!有高人能指点我一下吗? 论坛

SOCKET缓冲区的设置

07-01

在使用socket编程时(笔者使用socket完成进程间通信),往往会设置socket缓冲区的大小,偶有心得,分享给大家:rn(1)socket可以设置发送缓冲区和接受缓冲区。一般的操作步骤为:创建socket---bind---然后设置大小。socket缓冲区一旦设置,就不能随意更改,直到该socket被关闭。原因为 socket缓冲区是OS映射的一块动态内存,从应用层根本没有办法知道缓冲区的具体地址,也许你会说可以拿着socket的文件描述符去重新设置socket缓冲区大小,但这样显然不合适,因为原来缓冲区中的数据就没有了。rn(2)socket的缓冲区设置受两个因素制约,取决于怎么使用。rn I:基本说明,在/proc/sys/net/core/目录下有 wmem_default、rmem_default、wmem_max、rmem_max四个配置值。通俗的说就是四个配置项。申请的socket的缓冲区的大小受他们的限制。rn II:如果创建socket的时候,没有设置socket缓冲区的大小,那创建的socket缓冲区的最大值受default值的限制,既发送缓冲区为wmem_default;接受缓冲区为rmem_default。如果创建socket的时候,重新设置了socket缓冲区的大小,那此时socket缓冲区的大小就与default没有关系了,设置的socket缓冲区的值,最大不超过max的值。rn III:如果default的值比max的值大,会有什么效果?---[color=#FF0000]设置了缓冲区的大小反而没有默认的值大[/color],rn IV:拿这些配置项如何修改,很简单,就是文件的操作,先open,然后write,如:write(socketid,"204800\n",sizeof("204800\n"))就OK了。 论坛

没有更多推荐了,返回首页