繁体   English   中英

循环缓冲区的实现

[英]circular buffer implementation

再次是,我再次提出了非常简单的实现,如下所示:

    // write data always! if buffer is already full, overwrite old data!
    void Put( const CONTENT_TYPE &data )
    {
        buffer[ inOffset++] = data;
        inOffset%=size;

        // was data overwritten, skip it by increment read offset
        if ( inOffset == outOffset ) 
        {
            outOffset++;
            outOffset%=size;
            std::cout << "Overwrite" << std::endl;
        }
    }

    CONTENT_TYPE Pull()
    {
        CONTENT_TYPE data = buffer[ outOffset++ ];
        outOffset %= size;
        return data;
    }

但是,这种简单的算法仅利用大小为1的缓冲区元素!

如果我想避免这种情况,我只找到了添加另一个计数器变量的解决方案,这浪费了我sizeof(counter_var)-sizeof(element)个字节。

问:有没有不浪费内存的解决方案? 它看起来很简单,但我抓不到:-)

备注:还有更多的代码行可以保护空读取和其他内容,但这对这个问题并不重要。 而且它没有被标记为c ++,因为该算法不依赖于语言,即使我举一个c ++代码示例也是如此。

您可以使用两个整数并填充所有插槽(如果一个是索引,另一个是元素计数),然后立即进行转换以找到第二个索引:

void put(const ELEMENT& element) {
  if (nElements == size) throw "put: buffer full";
  buffer[(start + nElements++) % size] = element;
}

ELEMENT get() {
  if (nElements == 0) throw "get: buffer empty";
  ELEMENT& value = buffer[start];
  start = (start + 1) % size;
  --nElements;
  return value;
}

当然,您可以用if (foo > size) foo -= size;替换mod操作if (foo > size) foo -= size; 如果你喜欢。

您可以通过使用不同的时间点进行模运算来解决这个问题。 假设我们在每次访问后都增加了读写指针。 如果现在我们在增加之后立即执行读指针的模,而就在读之前立即写写指针的模,则| write-read | 完整缓冲区的长度将是缓冲区的长度,无需任何特殊情况处理。 为此,您的写指针应始终使用 % buffer_length ,但应存储 % (2 * buffer_length)

我不特别喜欢Mark的答案,因为按特殊情况处理事物通常不是一个好主意,在您通常使用size_t (即无符号整数)的地方,引入负的前哨值就少了。

您可以对偏移量之一使用特殊的前哨值,例如-1,以指示缓冲区已满或为空。 这会使检查和修改偏移量的代码复杂化。

// write data always! if buffer is already full, overwrite old data!
void Put( const CONTENT_TYPE &data )
{
    buffer[ inOffset++] = data;
    inOffset%=size;

    // was data overwritten, skip it by setting read offset to sentinel
    if ( inOffset == outOffset || outOffset == -1 ) 
    {
        outOffset = -1;
        std::cout << "Overwrite" << std::endl;
    }
}

CONTENT_TYPE Pull()
{
    if (outOffset == -1)
        outOffset = inOffset;
    CONTENT_TYPE data = buffer[ outOffset++ ];
    outOffset %= size;
    return data;
}

bool IsEmpty()
{
    return outOffset == inOffset;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM