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-2008 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 <gbxsickacfr/gbxutilacfr/exceptions.h> 00015 00016 #include <IceUtil/Monitor.h> 00017 #include <IceUtil/Mutex.h> 00018 #include <IceUtil/Time.h> 00019 00020 namespace gbxsickacfr { 00021 namespace gbxiceutilacfr { 00022 00039 template<class Type> 00040 class Store : public IceUtil::Monitor<IceUtil::Mutex> 00041 { 00042 public: 00043 00044 Store(); 00045 virtual ~Store(); 00046 00050 bool isEmpty() const; 00051 00053 bool isNewData() const; 00054 00056 void set( const Type & obj ); 00057 00061 void get( Type & obj ) const; 00062 00073 int getNext( Type & obj, int timeoutMs=-1 ) const; 00074 00077 void purge(); 00078 00079 protected: 00080 00081 // local copy of the object 00082 Type obj_; 00083 00084 // Reimplement this function for non-standard types. 00085 virtual void internalGet( Type & obj ) const ; 00086 00087 // Reimplement this function for non-standard types. 00088 virtual void internalSet( const Type & obj ); 00089 00090 private: 00091 00092 00093 bool isEmpty_; 00094 00095 // flag to keep track of new data. Make it mutable so that get() functions can be const. 00096 mutable bool isNewData_; 00097 00098 // internal implementation of front( obj, -1 ); returns 0. 00099 int getNextNoWait( Type & obj ) const; 00100 00101 }; 00102 00103 00105 00106 template<class Type> 00107 Store<Type>::Store() 00108 : isEmpty_(true), 00109 isNewData_(false) 00110 { 00111 } 00112 00113 template<class Type> 00114 Store<Type>::~Store() 00115 { 00116 } 00117 00118 template<class Type> 00119 bool Store<Type>::isEmpty() const 00120 { 00121 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00122 return isEmpty_; 00123 } 00124 00125 template<class Type> 00126 bool Store<Type>::isNewData() const 00127 { 00128 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00129 return isNewData_; 00130 } 00131 00132 template<class Type> 00133 void Store<Type>::get( Type & obj ) const 00134 { 00135 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00136 if ( !isEmpty_ ) 00137 { 00138 internalGet( obj ); 00139 isNewData_ = false; 00140 } 00141 else 00142 { 00143 throw gbxsickacfr::gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty Store." ); 00144 } 00145 } 00146 00147 template<class Type> 00148 int Store<Type>::getNext( Type & obj, int timeoutMs ) const 00149 { 00150 // special case: infinite wait time 00151 if ( timeoutMs == -1 ) { 00152 return getNextNoWait( obj ); 00153 } 00154 00155 // finite wait time 00156 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00157 00158 // if already have data in the buffer, return it and get out 00159 if ( isNewData_ ) 00160 { 00161 internalGet( obj ); 00162 isNewData_ = false; 00163 return 0; 00164 } 00165 00166 // empty buffer: figure out when to wake up 00167 // notice that we are still holding the lock, so it's ok to call timedWait() 00168 if ( this->timedWait( IceUtil::Time::milliSeconds( timeoutMs ) ) ) 00169 { 00170 // someone woke us up, we are holding the lock again 00171 // check new data again (could be a spurious wakeup) 00172 if ( isNewData_ ) 00173 { 00174 internalGet( obj ); 00175 isNewData_ = false; 00176 return 0; 00177 } 00178 else { 00179 // spurious wakup, don't wait again, just return 00180 return 1; 00181 } 00182 } 00183 else { 00184 // wait timedout, nobody woke us up 00185 return -1; 00186 } 00187 } 00188 00189 template<class Type> 00190 int Store<Type>::getNextNoWait( Type & obj ) const 00191 { 00192 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00193 00194 // check the condition before and after waiting to deal with spurious wakeups 00195 // (see Ice manual sec. 28.9.2) 00196 while ( !isNewData_ ) 00197 { 00198 this->wait(); 00199 } 00200 00201 internalGet( obj ); 00202 isNewData_ = false; 00203 return 0; 00204 } 00205 00206 // NOTE: see notes on efficient notification in Ice sec. 28.9.3 00207 template<class Type> 00208 void Store<Type>::set( const Type &obj ) 00209 { 00210 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00211 00212 internalSet( obj ); 00213 00214 // mark as having new data (nobody has looked at it yet) 00215 isNewData_ = true; 00216 00217 // mark Store non-empty (only usefull the very first time) 00218 isEmpty_ = false; 00219 00220 // wakeup someone who's waiting for an update 00221 this->notify(); 00222 } 00223 00224 template<class Type> 00225 void Store<Type>::purge() 00226 { 00227 IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this); 00228 isEmpty_ = true; 00229 } 00230 00231 template<class Type> 00232 void Store<Type>::internalGet( Type & obj ) const 00233 { 00234 obj = obj_; 00235 } 00236 00237 template<class Type> 00238 void Store<Type>::internalSet( const Type & obj ) 00239 { 00240 obj_ = obj; 00241 } 00242 00243 } 00244 } // end namespace 00245 00246 #endif |