INTRODUCTION Overview Download and Install Documentation Publications REPOSITORY Libraries DEVELOPER Dev Guide Dashboard PEOPLE Contributors Users Project Download Mailing lists
|
store.h00001 /* 00002 * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics 00003 http://gearbox.sf.net/ 00004 * Copyright (c) 2004-2010 Alex Brooks, Alexei Makarenko, Tobias Kaupp 00005 * 00006 * This distribution is licensed to you under the terms described in 00007 * the LICENSE file included in this distribution. 00008 * 00009 */ 00010 00011 #ifndef GBXICEUTILACFR_STORE_H 00012 #define GBXICEUTILACFR_STORE_H 00013 00014 #include <gbxutilacfr/exceptions.h> 00015 00016 #include <IceUtil/Monitor.h> 00017 #include <IceUtil/Mutex.h> 00018 #include <IceUtil/Time.h> 00019 00020 namespace gbxiceutilacfr { 00021 00041 template<class Type> 00042 class Store : public IceUtil::Monitor<IceUtil::Mutex> 00043 { 00044 public: 00045 00046 Store(); 00047 virtual ~Store(); 00048 00052 bool isEmpty() const; 00053 00055 bool isNewData() const; 00056 00058 void set( const Type & obj ); 00059 00063 void get( Type & obj ); 00064 00068 void peek( Type & obj ) const; 00069 00079 int getNext( Type & obj, int timeoutMs=-1 ); 00080 00083 void purge(); 00084 00085 protected: 00086 00087 // local copy of the object 00088 Type obj_; 00089 00090 // Reimplement this function for non-standard types. 00091 virtual void internalGet( Type & obj ) const ; 00092 00093 // Reimplement this function for non-standard types. 00094 virtual void internalSet( const Type & obj ); 00095 00096 private: 00097 00098 00099 bool isEmpty_; 00100 00101 // flag to keep track of new data. 00102 bool isNewData_; 00103 00104 // internal implementation of front( obj, -1 ); returns 0. 00105 int getNextNoWait( Type & obj ); 00106 00107 }; 00108 00109 00111 00112 template<class Type> 00113 Store<Type>::Store() 00114 : isEmpty_(true), 00115 isNewData_(false) 00116 { 00117 } 00118 00119 template<class Type> 00120 Store<Type>::~Store() 00121 { 00122 } 00123 00124 template<class Type> 00125 bool Store<Type>::isEmpty() const 00126 { 00127 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00128 return isEmpty_; 00129 } 00130 00131 template<class Type> 00132 bool Store<Type>::isNewData() const 00133 { 00134 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00135 return isNewData_; 00136 } 00137 00138 template<class Type> 00139 void Store<Type>::get( Type & obj ) 00140 { 00141 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00142 if ( !isEmpty_ ) 00143 { 00144 internalGet( obj ); 00145 isNewData_ = false; 00146 } 00147 else 00148 { 00149 throw gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty Store." ); 00150 } 00151 } 00152 00153 template<class Type> 00154 void Store<Type>::peek( Type & obj ) const 00155 { 00156 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00157 if ( !isEmpty_ ) 00158 { 00159 internalGet( obj ); 00160 // do NOT set isNewData_ to false 00161 } 00162 else 00163 { 00164 throw gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty Store." ); 00165 } 00166 } 00167 00168 template<class Type> 00169 int Store<Type>::getNext( Type & obj, int timeoutMs ) 00170 { 00171 // special case: infinite wait time 00172 if ( timeoutMs == -1 ) { 00173 return getNextNoWait( obj ); 00174 } 00175 00176 // finite wait time 00177 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00178 00179 // if already have data in the buffer, return it and get out 00180 if ( isNewData_ ) 00181 { 00182 internalGet( obj ); 00183 isNewData_ = false; 00184 return 0; 00185 } 00186 00187 // empty buffer: figure out when to wake up 00188 // notice that we are still holding the lock, so it's ok to call timedWait() 00189 if ( this->timedWait( IceUtil::Time::milliSeconds( timeoutMs ) ) ) 00190 { 00191 // someone woke us up, we are holding the lock again 00192 // check new data again (could be a spurious wakeup) 00193 if ( isNewData_ ) 00194 { 00195 internalGet( obj ); 00196 isNewData_ = false; 00197 return 0; 00198 } 00199 else { 00200 // spurious wakup, don't wait again, just return 00201 return 1; 00202 } 00203 } 00204 else { 00205 // wait timedout, nobody woke us up 00206 return -1; 00207 } 00208 } 00209 00210 template<class Type> 00211 int Store<Type>::getNextNoWait( Type & obj ) 00212 { 00213 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00214 00215 // check the condition before and after waiting to deal with spurious wakeups 00216 // (see Ice manual sec. 28.9.2) 00217 while ( !isNewData_ ) 00218 { 00219 this->wait(); 00220 } 00221 00222 internalGet( obj ); 00223 isNewData_ = false; 00224 return 0; 00225 } 00226 00227 // NOTE: see notes on efficient notification in Ice sec. 28.9.3 00228 template<class Type> 00229 void Store<Type>::set( const Type &obj ) 00230 { 00231 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00232 00233 internalSet( obj ); 00234 00235 // mark as having new data (nobody has looked at it yet) 00236 isNewData_ = true; 00237 00238 // mark Store non-empty (only usefull the very first time) 00239 isEmpty_ = false; 00240 00241 // wakeup someone who's waiting for an update 00242 this->notify(); 00243 } 00244 00245 template<class Type> 00246 void Store<Type>::purge() 00247 { 00248 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00249 isEmpty_ = true; 00250 } 00251 00252 template<class Type> 00253 void Store<Type>::internalGet( Type & obj ) const 00254 { 00255 obj = obj_; 00256 } 00257 00258 template<class Type> 00259 void Store<Type>::internalSet( const Type & obj ) 00260 { 00261 obj_ = obj; 00262 } 00263 00264 } // end namespace 00265 00266 #endif |