【问题标题】:c++ threadsafe ringbuffer implementation [closed]c ++线程安全环形缓冲区实现
【发布时间】:2013-09-27 20:14:32
【问题描述】:

我正在用 C++ 进行多线程编程,我想知道在 C++ 中是否有线程安全的 ringbuffer 实现,或者你知道如何实现它。

【问题讨论】:

  • 也许stackoverflow.com/questions/9743605/… 会回答你的问题
  • 您是否正在寻找只有一个线程写入而另一个线程读取的特殊情况?还是您想要一个通用的解决方案?
  • 实现任何线程安全的容器都相对容易,除非性能是您的驱动因素。您到底在寻找什么?
  • 我不知道区别,但我对一个写作和一个阅读线程感兴趣。性能对我来说很重要。
  • 环形缓冲区相对简单,如果递增的头部和尾部是原子的,那么你就可以 99% 实现线程安全。什么平台? (Windows/Linux)? Boost 可用吗?

标签: c++ thread-safety circular-buffer


【解决方案1】:

这是一个基本的实现。要求存储在缓冲区中的对象是默认可构造和可复制的(通过将它们存储在 std::vector 中)。需要C++11 支持(对于std::atomic)。大多数最新版本的gcc 都带有-std=c++11 或-std=c++0x

如果c++11 不可用,请用适当的编译器内部函数替换head_ 和tail_ 原子。

对于一个读取线程和一个写入线程应该是安全的。

通过调用发布项目:

  auto val = ringbuffer.back();
  val = some_value;
  ringbuffer.push();

通过调用检索项目:

  auto val = ringbuffer.front();
  // do stuff with val
  ringbuffer.pop();

如果back() 返回nullptr,则缓冲区“已满”。如果front() 返回nullptr,则缓冲区为“空”。

警告,未测试(完全):D

  #include <vector>

  template <class T>
  class RingBuffer
  {
  public:
     RingBuffer(size_t buffer_size)
        : ring_(buffer_size)
        , buffer_size_(buffer_size)
        , head_(0)
        , tail_(0)
     {
     }

     T* back()
     {
        bool received = false;

        if(available(head_, tail_))
        {
           return &(ring_[head_ % buffer_size_]);
        }

        return nullptr;
     }

     void push()
     {
        ++head_;
     }

     T* front()
     {
        if(tail_ < head_)
        {
           return & ring_[tail_ % buffer_size_];
        }

        return nullptr;
     }

     void pop()
     {
        ++tail_;
     }

     size_t size() const
     {
        if(tail_ < head_)
           return buffer_size_ - ((tail_ + buffer_size_) - head_);
        else if(tail_ > head_)
           return buffer_size_ - (tail_ - head_);

        return 0;
     }

     bool available()
     {
        return available(head_, tail_);
     }

  private:
     bool available(uint64_t h, uint64_t t) const
     {
        if(h == t)
           return true;
        else if(t > h)
           return (t - h) > buffer_size_;
        else// if(h > t)
           return (t + buffer_size_) - h > 0;
     }

     std::vector<T> ring_;
     const size_t   buffer_size_;
     std::atomic<uint64_t> head_;
     std::atomic<uint64_t> tail_;
  };

【讨论】:

  • 我不明白您所说的“如果 c++11 不可用,请替换适当的编译器内在函数以使 head_ 和 tail_ 成为原子。”
  • head_ 和 tail_ 需要是原子的,这意味着修改(或读取它们的值)应该是原子操作。如果你不明白这意味着什么,那么我认为你可能还没有准备好进行多线程编程。
  • 嗯。不知道我明白了。例如size 是否容易受到从另一个线程调用的push 的影响,并在if 和return 之间更改head_ 的值?
  • 从一个线程进入(到该函数)时大小是正确的。对 size 的两个后续调用可能会返回不同的值。但它未经测试。
  • 我认为这根本不是线程安全的,因为您可以随时调用 front() 或 back(),挂在指针上并修改底层数据。为了使其线程安全,我认为您需要提供“push(somedata)/pop”并将对 ring_ 的访问权限封装在内部的互斥锁中,或者将对此类的所有访问权限封装在外部的互斥锁中。我不是专家,但我认为目前原子并没有真正做任何事情来保护数据本身。
猜你喜欢
  • 2016-12-26
  • 2012-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-04
  • 1970-01-01
  • 1970-01-01
  • 2010-09-17
相关资源
最近更新 更多