Wefts::RingBuffer< _T > Class Template Reference
[Advanced Syncronization constructs]

#include <wefts_ringbuffer.h>

Inheritance diagram for Wefts::RingBuffer< _T >:

Inheritance graph
[legend]
Collaboration diagram for Wefts::RingBuffer< _T >:

Collaboration graph
[legend]
List of all members.

Detailed Description

template<typename _T>
class Wefts::RingBuffer< _T >

Ring buffer synchronization object.

A synchronized ring buffer is an object that allows safe communications between a set of producers (threads providing data) and a set of consumers (threads willing to receive the data provided).

A ring buffer is made of a finite number of cells, allocated in a buffer that can be read or written from the first to the last element; when an element is read, the read-pointer is moved one step forward; when an element is written, a write pointer is moved forward. When one of this pointers reach the last element, it is moved to the first element again. The buffer is full if the write pointer makes a full loop and reaches the cell pointed by the read pointer, and is empty if the read pointer precedes the write pointer by one position.

Readers and writers are continuously changing the status of the buffer, so that it is absolutely necessary to handle all the data relative to the pointer with just one mutex: a read MUST NOT HAPPEN while a write is done and vice-versa; also two contemporary reads or writes must be forbidden. But here we have two kind of threads, interested in two different kind of events (or predicates). If the buffer is empty, the readers must wait for it being filled again before to proceed, while if the ring is full, the writers must wait for it having some free position again.

The order in which readers can access the data in the buffer is random and depends from the moment they are awaken by the OS.

Ring buffers can be used in various ways. One way is just to make sure that data needed to be processed is sent to the available processors as fast as one of them is ready, and that none of the produced data is lost.

Another typical use is to allow the "plug in" of new producers when requests peaks at some moment of the process, or to plug in new consumers if the system has a temporary abundance of CPU.

Also, maintaining constant the number of consumers and producers, ring buffers acts as a cushion allowing to have consumers with very different processing time without blocking the throughput of requests.

Another use is to check the performance of producers and consumers; providing a ringbuffer that has at least an amount of cell greater or equal to the double of the readers, it is possible to write algorithms that try to maintain the "fill" level of the ring buffer around a given percentage; in any moment, the amount of requests left to process is an indicator of the efficiency of the process, so a process having a nearly empty ring buffer may want to "relax" its reading rhythm, so to free more CPU for the system without loosing promptness in processing, while a process having a nearly filled ring buffer may want to speed up its operations, or slow down process acceptance.

A ring buffer that stays filled for a too long time can be detected to start disaster recovery operations, to warn the administrators or the users.

Finally, a special kind of ringbuffer, having just one cell, may be used just to queue several requests from different sources, and allow them to pass just one at a time.

Todo:
variable length ringbuffers


Public Member Functions

 RingBuffer (const unsigned long size) throw ( InitError )
 Creates the buffer.

 ~RingBuffer ()
unsigned long size () const
 Returns the allocated size of the ringbuffer.

unsigned long free ()
 Free elements in the buffer.

void write (_T data)
 Waits until space is available in the buffer, and then writes the parameter.

_T read ()
bool tryWrite (_T data)
 Tries to write the data.

bool tryRead (_T &data)
 Tries to read some data from the buffer.

virtual void handleCleanup (int pos, void *)
 Cleanup for deferred cancellation.


Private Member Functions

bool empty () const
 Tells if a ringbuffer is empty.

bool full () const
 Tells if a ringbuffer is empty.

void put (_T data)
 Does the raw job of putting the data into the buffer.

_T get ()
 Does the raw job of getting the data from the buffer.


Private Attributes

Mutex m_mutex
Condition m_rCond
Condition m_wCond
_T * m_buffer
 The buffer.

unsigned long m_size
 The size of the buffer.

unsigned long m_wPos
 write pointer

unsigned long m_rPos
 read pointer

int m_wWaiting
 writers waiting

int m_rWaiting
 readers waiting


Constructor & Destructor Documentation

template<typename _T>
Wefts::RingBuffer< _T >::RingBuffer const unsigned long  size  )  throw ( InitError ) [inline]
 

Creates the buffer.

A size greater than zero must be given; if the size is so big that the required memory can't be allocated, or if zero is given as an argument, the constructor throws an InitError.

template<typename _T>
Wefts::RingBuffer< _T >::~RingBuffer  )  [inline]
 


Member Function Documentation

template<typename _T>
bool Wefts::RingBuffer< _T >::empty  )  const [inline, private]
 

Tells if a ringbuffer is empty.

This function is private as trying to see if a ringbuffer is full or empty makes sense only from within a read or write call (inside a locked mutex area).

template<typename _T>
unsigned long Wefts::RingBuffer< _T >::free  )  [inline]
 

Free elements in the buffer.

If writers and readers are running this number normally does not make sense; it is provided just to debug the code or to have a status when no other thread is working on this object.

Anyhow, it makes a lot of sense if used to periodically check the status of the buffer, or to produce statistical data, or to monitor the status of a process etc.

In other words it gets significance if used in statistical analysis of the buffer status, while it's punctual value is meaningless.

Returns:
number of free elemnts in the ring buffer.

template<typename _T>
bool Wefts::RingBuffer< _T >::full  )  const [inline, private]
 

Tells if a ringbuffer is empty.

This function is private as trying to see if a ringbuffer is full or empty makes sense only from within a read or write call (inside a locked mutex area).

template<typename _T>
_T Wefts::RingBuffer< _T >::get  )  [inline, private]
 

Does the raw job of getting the data from the buffer.

Call it only once a thread knows that a write can be done, and while the thread is holding the mutex.

template<typename _T>
virtual void Wefts::RingBuffer< _T >::handleCleanup int  pos,
void * 
[inline, virtual]
 

Cleanup for deferred cancellation.

Users must never call this method.

Implements Wefts::CleanupHandler.

template<typename _T>
void Wefts::RingBuffer< _T >::put _T  data  )  [inline, private]
 

Does the raw job of putting the data into the buffer.

Call it only once a thread knows that a write can be done, and while the thread is holding the mutex.

template<typename _T>
_T Wefts::RingBuffer< _T >::read  )  [inline]
 

template<typename _T>
unsigned long Wefts::RingBuffer< _T >::size  )  const [inline]
 

Returns the allocated size of the ringbuffer.

template<typename _T>
bool Wefts::RingBuffer< _T >::tryRead _T &  data  )  [inline]
 

Tries to read some data from the buffer.

This method never waits; if some data is immediately available to be pulled out from the buffer, the parameter value is overwritten and the method retunrs true; else, it returns false, and the parameter is left untouched.

Parameters:
data a variable that will contain the read data on success.
Returns:
true if some data has been read from the buffer.

template<typename _T>
bool Wefts::RingBuffer< _T >::tryWrite _T  data  )  [inline]
 

Tries to write the data.

This method never waits; if the data can't be written because the buffer is full, it returns false, else it returns true.

Parameters:
data the data to be put in the buffer.
Returns:
true if data can be written.

template<typename _T>
void Wefts::RingBuffer< _T >::write _T  data  )  [inline]
 

Waits until space is available in the buffer, and then writes the parameter.

Parameters:
data the element to write in the buffer.


Member Data Documentation

template<typename _T>
_T* Wefts::RingBuffer< _T >::m_buffer [private]
 

The buffer.

template<typename _T>
Mutex Wefts::RingBuffer< _T >::m_mutex [private]
 

template<typename _T>
Condition Wefts::RingBuffer< _T >::m_rCond [private]
 

template<typename _T>
unsigned long Wefts::RingBuffer< _T >::m_rPos [private]
 

read pointer

template<typename _T>
int Wefts::RingBuffer< _T >::m_rWaiting [private]
 

readers waiting

template<typename _T>
unsigned long Wefts::RingBuffer< _T >::m_size [private]
 

The size of the buffer.

template<typename _T>
Condition Wefts::RingBuffer< _T >::m_wCond [private]
 

template<typename _T>
unsigned long Wefts::RingBuffer< _T >::m_wPos [private]
 

write pointer

template<typename _T>
int Wefts::RingBuffer< _T >::m_wWaiting [private]
 

writers waiting


The documentation for this class was generated from the following file:
Generated on Tue Oct 5 14:57:03 2004 for Wefts by doxygen 1.3.7