• 【转】环形缓冲区


    原文地址:http://blog.csdn.net/linlinlinxi007/article/details/5086806

    在通信程序中,经常使用环形缓冲区作为数据结构来存放通信中发送和接收的数据。环形缓冲区是一个先进先出的循环缓冲区,可以向通信程序提供对缓冲区的互斥访问。 

    1、环形缓冲区的实现原理 
    环形缓冲区通常有一个读指针和一个写指针。读指针指向环形缓冲区中可读的数据,写指针指向环形缓冲区中可写的缓冲区。通过移动读指针和写指针就可以实现缓冲区的数据读取和写人。在通常情况下,环形缓冲区的读用户仅仅会影响读指针,而写用户仅仅会影响写指针。如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以保证数据的正确性。如果有多个读写用户访问环形缓冲区,那么必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。 
    图1、图2和图3是一个环形缓冲区的运行示意图。图1是环形缓冲区的初始状态,可以看到读指针和写指针都指向第一个缓冲区处;图2是向环形缓冲区中添加了一个数据后的情况,可以看到写指针已经移动到数据块2的位置,而读指针没有移动;图3是环形缓冲区进行了读取和添加后的状态,可以看到环形缓冲区中已经添加了两个数据,已经读取了一个数据。 

    服务器公共组件实现----环形缓冲区 


      消息队列锁调用太频繁的问题算是解决了,另一个让人有些苦恼的大概是这太多的内存分配和释放操作了。频繁的内存分配不但增加了系统开销,更使得内存碎片不断增多,非常不利于我们的服务器长期稳定运行。也许我们可以使用内存池,比如SGI STL中附带的小内存分配器。但是对于这种按照严格的先进先出顺序处理的,块大小并不算小的,而且块大小也并不统一的内存分配情况来说,更多使用的是一种叫做环形缓冲区的方案,mangos的网络代码中也有这么一个东西,其原理也是比较简单的。 
      就好比两个人围着一张圆形的桌子在追逐,跑的人被网络IO线程所控制,当写入数据时,这个人就往前跑;追的人就是逻辑线程,会一直往前追直到追上跑的人。如果追上了怎么办?那就是没有数据可读了,先等会儿呗,等跑的人向前跑几步了再追,总不能让游戏没得玩了吧。那要是追的人跑的太慢,跑的人转了一圈过来反追上追的人了呢?那您也先歇会儿吧。要是一直这么反着追,估计您就只能换一个跑的更快的追逐者了,要不这游戏还真没法玩下去。 
      前面我们特别强调了,按照严格的先进先出顺序进行处理,这是环形缓冲区的使用必须遵守的一项要求。也就是,大家都得遵守规定,追的人不能从桌子上跨过去,跑的人当然也不允许反过来跑。至于为什么,不需要多做解释了吧。 
      环形缓冲区是一项很好的技术,不用频繁的分配内存,而且在大多数情况下,内存的反复使用也使得我们能用更少的内存块做更多的事。 
      在网络IO线程中,我们会为每一个连接都准备一个环形缓冲区,用于临时存放接收到的数据,以应付半包及粘包(即发送方发送的若干包数据到接收方接收时粘成一包)的情况。在解包及解密完成后,我们会将这个数据包复制到逻辑线程消息队列中,如果我们只使用一个队列,那这里也将会是个环形缓冲区,IO线程往里写,逻辑线程在后面读,互相追逐。可要是我们使用了前面介绍的优化方案后,可能这里便不再需要环形缓冲区了,至少我们并不再需要他们是环形的了。因为我们对同一个队列不再会出现同时读和写的情况,每个队列在写满后交给逻辑线程去读,逻辑线程读完后清空队列再交给IO线程去写,一段固定大小的缓冲区即可。没关系,这么好的技术,在别的地方一定也会用到的   

    2、实例:环形缓冲区的实现

    环形缓冲区是数据通信程序中使用最为广泛的数据结构之一,下面的代码,实现了一个环形缓冲区:

     1 /*ringbuf .c*/
     2 #include<stdio.h>
     3 #include<ctype.h>
     4 
     5 #define NMAX 8
     6 
     7 int iput = 0; /* 环形缓冲区的当前放入位置 */
     8 int iget = 0; /* 缓冲区的当前取出位置 */
     9 int n = 0; /* 环形缓冲区中的元素总数量 */
    10 double buffer[NMAX];
    11 
    12 /* 环形缓冲区的地址编号计算函数,如果到达唤醒缓冲区的尾部,将绕回到头部。环形缓冲区的有效地址编号为:0到(NMAX-1)*/
    13 int addring(int i)
    14 {
    15      return (i+1) == NMAX ? 0 : i+1;
    16 }
    17 
    18 /* 从环形缓冲区中取一个元素 */
    19 double get(void)
    20 {
    21         int Pos;
    22         if (n>0)
    23         {
    24              Pos = iget;
    25              iget = addring(iget);
    26              n--;
    27              return buffer[Pos];
    28         }
    29         else 
    30         {
    31             printf("Buffer is empty/n");
    32             return 0.0;
    33         }       
    34  }
    35 
    36 /* 向环形缓冲区中放入一个元素*/
    37 void put(double z)
    38 {
    39         if (n<NMAX)
    40         {
    41              buffer[iput]=z;
    42              iput = addring(iput);
    43              n++;
    44         }
    45         else
    46             printf("Buffer is full/n");
    47 }
    48 
    49  
    50 
    51 int main(void)
    52 {
    53         char opera[5];
    54         double z;
    55         do 
    56         {
    57             printf("Please input p|g|e?");
    58             scanf("%s", &opera);
    59             switch(tolower(opera[0]))
    60             {
    61                    case 'p': /* put */
    62                        printf("Please input a float number?");
    63                        scanf("%lf", &z);
    64                        put(z);
    65                        break;
    66                     case 'g': /* get */
    67                         z = get();
    68                         printf("%8.2f from Buffer/n", z);
    69                         break;
    70                     case 'e':
    71                         printf("End/n");
    72                         break;
    73                     default:
    74                         printf("%s - Operation command error! /n", opera);
    75             }/* end switch */
    76         }while(opera[0] != 'e');
    77         return 0;
    78 }
  • 相关阅读:
    Windows 7 Phone 文档数据库Rapid Repository正式发布
    Adobe展示HTML5动画制作IDE
    详解Android实现全屏正确方法
    qtform.com计划
    Adobe加速布局移动开发:Flash Builder+Flex+AIR+Catalyst
    预览:Visual Basic与C#中的异步语法
    Windows 7主题中的壁纸从哪里来?
    F#的编译器及标准库使用Apache 2.0协议开源(暂时还没有看到未来)
    开发者谈Symbian、iPhone、Android、MeeGo平台
    MeeGo 1.1发布
  • 原文地址:https://www.cnblogs.com/codecamel/p/4682357.html
Copyright © 2020-2023  润新知