00001 /* 00002 wefts_ringbuffer.h 00003 Ringbuffer sync object 00004 00005 $Id: wefts_ringbuffer.h,v 1.4 2004/03/28 21:45:40 jonnymind Exp $ 00006 --------------------------------------------- 00007 Begin : 2003-08-16 21:25 00008 Author : Giancarlo Niccolai 00009 00010 Last modified because: 00011 00012 */ 00013 00014 /************************************************************************** 00015 * This program is free software; you can redistribute it and/or modify * 00016 * it under the terms of the GNU Library General Public License as * 00017 * published by the Free Software Foundation; either version 2.1 of the * 00018 * License, or (at your option) any later version. * 00019 ***************************************************************************/ 00020 00021 #ifndef WT_RINGBUFFER_H 00022 #define WT_RINGBUFFER_H 00023 00024 #include <wefts_mutex.h> 00025 #include <wefts_cond.h> 00026 #include <wefts_cleanup.h> 00027 #include <iostream> 00028 00029 namespace Wefts { 00030 00095 template < typename _T > 00096 class RingBuffer: public CleanupHandler 00097 { 00098 private: 00099 Mutex m_mutex; 00100 Condition m_rCond; 00101 Condition m_wCond; 00102 00104 _T *m_buffer; 00105 00107 unsigned long m_size; 00108 00110 unsigned long m_wPos; 00112 unsigned long m_rPos; 00113 00115 int m_wWaiting; 00117 int m_rWaiting; 00118 00124 bool empty() const { 00125 return ( m_wPos == m_rPos + 1|| 00126 (m_size > 1 &&m_wPos == 0 && m_rPos == m_size-1) ); 00127 } 00128 00134 bool full() const { 00135 return (m_wPos == m_rPos); 00136 } 00137 00143 void put( _T data ) { 00144 00145 bool was_empty = empty(); 00146 if ( m_size == 1 ) { 00147 *m_buffer = data; 00148 m_wPos = 0; 00149 } 00150 else { 00151 m_buffer[ m_wPos ++ ] = data; 00152 if ( m_wPos == m_size ) m_wPos = 0; 00153 } 00154 00155 if( was_empty && m_rWaiting != 0 ) 00156 m_rCond.signal(); // tell the readers situation has changed. 00157 } 00158 00159 00164 _T get() { 00165 bool was_full = full(); 00166 00167 if ( m_rPos == m_size -1) 00168 m_rPos = 0; 00169 else 00170 m_rPos++; 00171 00172 if( was_full && m_wWaiting != 0 ) { 00173 m_wCond.signal(); 00174 } 00175 if ( m_size == 1 ) m_wPos = 1; 00176 00177 return m_buffer[ m_rPos ]; 00178 } 00179 00180 00181 public: 00182 00189 RingBuffer ( const unsigned long size ) throw( InitError ) 00190 { 00191 if ( size == 0 ) throw InitError(); 00192 m_buffer = new _T[ size ]; 00193 if ( m_buffer == 0 ) throw InitError(); 00194 00195 m_size = size; 00196 00197 m_wPos = 1; 00198 m_rPos = 0; 00199 m_wWaiting = 0; 00200 m_rWaiting = 0; 00201 00202 m_wCond.setMutex( &m_mutex ); 00203 m_rCond.setMutex( &m_mutex ); 00204 } 00205 00206 ~RingBuffer() { delete m_buffer; } 00207 00209 unsigned long size() const { m_size; } 00210 00224 unsigned long free() { 00225 unsigned long ret; 00226 00227 m_mutex.lock(); 00228 if ( m_wPos > m_rPos ) 00229 m_ret = m_size -m_wPos + m_rPos + 1; 00230 else 00231 m_ret = m_rPos - m_wPos; 00232 m_mutex.unlock(); 00233 00234 return ret; 00235 } 00236 00240 void write( _T data ) 00241 { 00242 m_mutex.lock(); 00243 00244 // have we to wait? 00245 if( full() ) { 00246 m_wWaiting++; 00247 while ( full() ) { 00248 // position == 0 --> cleanup a writer 00249 m_wCond.wait( this, 0 ); 00250 } 00251 m_wWaiting--; 00252 } 00253 put( data ); 00254 00255 m_mutex.unlock(); 00256 } 00257 00258 /* Waits until some data may be read and returns the read data. 00259 \return The element that has been read from the buffer. 00260 */ 00261 _T read() 00262 { 00263 m_mutex.lock(); 00264 00265 // have we to wait? 00266 if( empty() ) { 00267 m_rWaiting++; 00268 while ( empty() ) { 00269 // position == 1 --> cleanup a reader 00270 m_rCond.wait( this, 1 ); 00271 } 00272 m_rWaiting--; 00273 } 00274 _T data = get(); 00275 m_mutex.unlock(); 00276 return data; 00277 } 00278 00279 00287 bool tryWrite( _T data ) { 00288 bool ret; 00289 00290 m_mutex.lock(); 00291 if ( ! full() ) { 00292 put( data ); 00293 ret = true; 00294 } 00295 else 00296 ret = false; 00297 m_mutex.unlock(); 00298 00299 return ret; 00300 } 00301 00309 bool tryRead( _T &data ) { 00310 bool ret; 00311 00312 m_mutex.lock(); 00313 if ( ! empty() ) { 00314 data = get(); 00315 ret = true; 00316 } 00317 else 00318 ret = false; 00319 m_mutex.unlock(); 00320 00321 return ret; 00322 } 00323 00327 virtual void handleCleanup( int pos, void * ) 00328 { 00329 if ( pos == 0 ) 00330 // cleanup a writer 00331 m_wWaiting--; 00332 else 00333 // cleanup a reader 00334 m_rWaiting--; 00335 00336 m_mutex.unlock(); 00337 } 00338 }; 00339 00340 } 00341 #endif 00342 00343 /* end wefts_ringbuffer.h */