循环缓冲区的实现
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操作
你可以通过在不同的时间点做模运算来解决这个问题;假设我们在每次访问后增加读和写指针。如果我们现在在递增之后立即对读指针取模,并在读取之前对写指针取模,则整个缓冲区的|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;
}
相关文章:
- 如何使用ZeroMQ为协议缓冲区编写自己的RPC实现
- 只有第一个缓冲区可以在C++中实现的Double缓冲区中工作
- 有没有办法自动实现 sprintf 的缓冲区分配?
- 在 Windows 中使用 boost::asio 实现最佳缓冲区大小
- 了解循环缓冲区实现的内存分配性质
- 如何从uint8_t的缓冲区读取带符号整数,而不调用未定义或实现定义的行为
- CUDA中一个简单Z缓冲区的实现
- 测试环形缓冲区实现的"cache not flushed to main memory"
- Google 协议缓冲区C++在面对恶意数据时实现稳定性和安全性
- 使用 deque 在C++中实现循环缓冲区
- 内部套接字接收缓冲区实现
- C++ 线程安全环缓冲区实现
- 循环缓冲区的线程安全实现.来自 boost 库的
- 在C++中使用 fread 时实现固定大小缓冲区的最佳方法是什么?
- 实现任意类型擦除的小缓冲区优化的简单方法(如std::function.)
- 为浮点值实现一个简单的环形缓冲区
- c++ std::deque实现:为什么不使用循环缓冲区
- 是否可以使用 Varint32 大小前缀的协议缓冲区消息实现类似"FileInputStream::BackUp()"的功能?
- 为文本编辑控件实现缓冲区的最佳方法是什么?
- 实现定义的行为和将unicode读取到缓冲区