【问题标题】:Boost atomic: wait-free ring buffer with large amount of dataBoost atomic:具有大量数据的无等待环形缓冲区
【发布时间】:2013-05-31 16:51:42
【问题描述】:

我想使用boost::atomic 作为此处所述的无等待环形缓冲区:

Boost Example

我的producer 同时提供大量数据(无符号字符,+- 3000 个值),就像它会逐行填充的矩阵一样。在缓冲区中push 这些值的最佳方法是什么?我应该直接遍历它们还是可以memcpy它们以某种方式进入它们?

如果我想同时读取一堆值,pop 也是如此......


这是我想出的,有什么理由不应该是好的? 我只需要确定RINGBUFFERSIZE % iSize = 0

#define RINGBUFFERSIZE = 30000

ring_[RINGBUFFERSIZE];

bool push(unsigned char* iData, int iSize)
{
    size_t head = head_.load(boost::memory_order_relaxed);
    size_t next_head = next(head,iSize);
    if (next_head == tail_.load(boost::memory_order_acquire))
    return false;
    memcpy(ring_+head,iData,iSize);
    head_.store(next_head, boost::memory_order_release);
}

bool pop(unsigned char * value, int iSize)
{
     size_t tail = tail_.load(boost::memory_order_relaxed);
     if (tail == head_.load(boost::memory_order_acquire))
         return false;
     value = &ring_[tail];
     tail_.store(next(tail,iSize), boost::memory_order_release);
     return true;
}


size_t next(size_t current, int iSize)
{
     return (current + iSize) % RINGBUFFERSIZE;
}

【问题讨论】:

  • 建议的解决方案不太奏效,因为next_head 可能已经结束了。在这种情况下,您没有连续的块并且不能执行单个memcpy(当然您可以检查这种情况,也许可以执行两个)。

标签: c++ boost atomic circular-buffer


【解决方案1】:

最快的方法是压入一个指针(unsigned char * 或指向包含长度的某个结构的指针)。

当然,假设可以强制 pop 获取与推送完全相同的块,这只是解决了问题:现在您必须以某种方式管理这些缓冲区的分配。


用于管理块的简单示例解决方案:

  1. 预分配“足够”的固定大小块对象(比如动态长度 + unsigned char data[3096] 或其他)
  2. 在您的无等待环形缓冲区中发送一个块的地址
  3. 当消费者使用完后,将地址返回到另一个环形缓冲区,这样生产者就可以回收相同的块对象

如果你真的不能这样做,你可以为你的块选择一个最大尺寸并按值推送/弹出该尺寸的对象......但老实说,这似乎非常浪费(即使对象知道它的长度,因此不必memcpy 整个 3k 数组用于更小的块)。

【讨论】:

  • 没错,指向的内存将不再有效,所以我需要自己复制数据。
  • 您确定控制缓冲区的有效性吗?
  • 数据来自tcp连接,所以每次读取都需要存储。
  • 是的,但是您读入的内存的分配和生命周期管理在您的控制之下......除非您特别关注重新组装部分读取?
  • 你当然可以这样做,但我认为使用这个容器(它面向离散值对象而不是可变长度数据流)并不容易
猜你喜欢
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
  • 2014-10-30
  • 2020-04-09
  • 2022-11-11
  • 2015-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多