Boost logo

Boost Users :

From: Selçuk Giray Özdamar (selcukgiray_at_[hidden])
Date: 2008-06-12 04:34:50


 Hi everyone, I wrote my template based CircularBuffer class. Here the
primary aim is to make everything thread safe. Multiple concurrent reads are
possible, but only exclusive write is possible.

 Here we have index operator overloaded. As usual index operator has 2
versions, const and non-const versions.

  T& operator [] (unsigned index); // return as reference
  T operator [] (unsigned index) const; // return by value

 In contrast, standart library container classes return by const reference
in const methods. Here I'm returning by value.

 Below you can see my complete implementation. There may be possible
potential risks here. For example, in overloaded index operator (const
function) it returns by value, so read lock assures it's safety. But I can't
say the same things for non-const function which returns reference.

 If you write something like this: T& _refT = mCircularBuffer[0];
 It returns as reference, and some other time you are free to change the
value of _refT (after leaving the index operator scope). So write lock is
unlocked, and as a consequence it's not thread safe so.

 And also iterators are same as the index operator, not thread safe.

 I'm looking for much safer implementation.

 Thanks, regards...

 template <class T>
 class CircularBuffer
 {
  typedef boost::shared_mutex ReadWriteMutex;
  typedef boost::shared_lock<boost::shared_mutex> ReadLock;
  typedef boost::unique_lock<boost::shared_mutex> WriteLock;

 public:

  // A const (random access) iterator used to iterate through the
circular_buffer
  typedef typename boost::circular_buffer<T>::const_iterator const_iterator;

  // A (random access) iterator used to iterate through the circular_buffer
  typedef typename boost::circular_buffer<T>::iterator iterator;

  explicit CircularBuffer(unsigned capacity = 10)
   : m_capacity(capacity)
   , m_buffer(capacity)
  {
  }

  ~CircularBuffer()
  {
  }

  CircularBuffer(const CircularBuffer& other)
   : m_capacity(other.m_capacity)
   , m_buffer(other.m_buffer)
  {
  }

  CircularBuffer& operator= (const CircularBuffer& other)
  {
   CircularBuffer temp(other);

   WriteLock w_lock(rw_mutex);

   using std::swap;
   swap(m_capacity, temp.m_capacity);
   swap(m_buffer, temp.m_buffer);

   return *this;
  }

  // Get the iterator pointing to the beginning of the
<code>circular_buffer</code>.
  iterator begin()
  {
   WriteLock w_lock(rw_mutex);
   return m_buffer.begin();
  }

  // Get the iterator pointing to the end of the
<code>circular_buffer</code>.
  iterator end()
  {
   WriteLock w_lock(rw_mutex);
   return m_buffer.end();
  }

  // Get the const iterator pointing to the beginning of the
<code>circular_buffer</code>
  const_iterator begin() const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.begin();
  }

  // Get the const iterator pointing to the end of the
<code>circular_buffer</code>.
  const_iterator end() const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.end();
  }

  T& operator [] (unsigned index)
  {
   WriteLock w_lock(rw_mutex);
   return m_buffer[index];
  }

  T operator [] (unsigned index) const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer[index];
  }

  T& at(unsigned index)
  {
   WriteLock w_lock(rw_mutex);
   return m_buffer.at(index);
  }

  T at(unsigned index) const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.at(index);
  }

  T& front()
  {
   WriteLock w_lock(rw_mutex);
   return m_buffer.front();
  }

  T& back()
  {
   WriteLock w_lock(rw_mutex);
   return m_buffer.back();
  }

  T front() const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.front();
  }

  T back() const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.back();
  }

  size_t size() const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.size();
  }

  bool empty() const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.empty();
  }

  bool full() const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.full();
  }

  size_t capacity() const
  {
   ReadLock r_lock(rw_mutex);
   return m_buffer.capacity();
  }

  void push_back(const T& item = T())
  {
   WriteLock w_lock(rw_mutex);
   m_buffer.push_back(item);
  }

  void clear()
  {
   WriteLock w_lock(rw_mutex);
   m_buffer.clear();
  }

 private:
  unsigned m_capacity;
  boost::circular_buffer<T> m_buffer;

  // rw_mutex for internal buffer
  mutable ReadWriteMutex rw_mutex;
 };



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net