Chinaunix首页 | 论坛 | 博客
  • 博客访问: 331107
  • 博文数量: 100
  • 博客积分: 2620
  • 博客等级: 少校
  • 技术积分: 920
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-16 02:50
文章分类

全部博文(100)

文章存档

2011年(5)

2010年(12)

2009年(83)

分类:

2009-12-16 11:37:59

mangos 之 CircularBuffer
  
    循环缓冲区是应用比较广泛的数据结构了,mangos也用到了,但是mangos中的CircularBuffer有点不一样,就是其内部将用户指定的缓冲区大小double了一下,而往缓冲区中添加数据的函数也有点小区别,看看代码先:
bool CircularBuffer::Write(const char *s,size_t l)
{
 if (m_q + l > m_max)
 {
  m_owner.Handler().LogError(&m_owner, "CircularBuffer::Write", -1, "write buffer overflow");
  return false; // overflow
 }
 m_count += (unsigned long)l;
 if (m_t + l > m_max) // block crosses circular border
 {
  size_t l1 = m_max - m_t; // size left until circular border crossing
  // always copy full block to buffer(buf) + top pointer(m_t)
  // because we have doubled the buffer size for performance reasons
  memcpy(buf + m_t, s, l); //////////////////////(A)
  memcpy(buf, s + l1, l - l1);
  m_t = l - l1;
  m_q += l;
 }
 else
 {
  memcpy(buf + m_t, s, l);     /////(B1)
  memcpy(buf + m_max + m_t, s, l); //////////////////(B)
  m_t += l;
  if (m_t >= m_max)
   m_t -= m_max;
  m_q += l;
 }
 return true;
}
    在(A)的地方,没有memcpy l1的长度,而是l长度,即s中的后l-l1个字节拷贝到了缓冲区的后半部分去。
   在(B)处本来可以调用一次memcpy(即B1)就可以搞定的,还又调用了一次B,将数据写到缓冲区后半部分对应的区域。
一开始没有理解怎么回事,这不是画蛇添足么。后来发现mangos的CircularBuffer类还提供了几个函数:GetStart,SoftRead和Remove,他们就是让用户直接操控循环缓冲区指针的接口。用户不可能处理CircularBuffer跨越边界的问题,所有用户看到的都是连续的区域。通过上面A,B的处理,即使发生跨越边界的点,用户也可以取到正确的数据。这种方式不错,呵呵!
   另外,codeproject上有个BipBuffer也是类似的(),需要向用户提供连续空间的指针,它是通过划分区域来实现的,分配的时候就直接分配连续的空间,避免了分段的发生。BipBuffer值负责管理缓冲区,即它只负责给你一块空间(Reserve),你自己写,写好了告诉它(Commit)。这种方式可能会在某些时刻浪费一部分缓冲区空间,即用潜在的空间浪费换取连续空间。
阅读(1432) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~