monitor.cpp

Go to the documentation of this file.
00001 
00014 #include <dlrThread/exception.h>
00015 #include <dlrThread/monitor.h>
00016 #include <dlrThread/private.h>
00017 
00018 
00019 namespace dlr {
00020 
00021   namespace thread {
00022 
00023 
00024     Token::
00025     Token()
00026       : m_isTimed(false),
00027         m_lockPtr(0),
00028         m_timedLockPtr(0),
00029         m_referenceCount(0)
00030     {
00031       // Empty.
00032     }
00033 
00034     
00035     Token::
00036     Token(const Token& other)
00037       : m_isTimed(other.m_isTimed),
00038         m_lockPtr(other.m_lockPtr),
00039         m_timedLockPtr(other.m_timedLockPtr),
00040         m_referenceCount(other.m_referenceCount)
00041     {
00042       // Empty.
00043     }
00044 
00045 
00046     Token&
00047     Token::
00048     operator=(const Token& other)
00049     {
00050       if(this != &other) {
00051         m_isTimed = other.m_isTimed;
00052         m_lockPtr = other.m_lockPtr;
00053         m_timedLockPtr = other.m_timedLockPtr;
00054         m_referenceCount = other.m_referenceCount;
00055       }
00056       return *this;
00057     }
00058     
00059 
00060     Token::
00061     Token(boost::timed_mutex& mutex)
00062       : m_isTimed(false),
00063         m_lockPtr(new boost::timed_mutex::scoped_lock(mutex)),
00064         m_timedLockPtr(0),
00065         m_referenceCount()
00066     {
00067       // Empty.
00068     }
00069 
00070 
00071     Token::
00072     Token(boost::timed_mutex& mutex, double timeout)
00073       : m_isTimed(true),
00074         m_lockPtr(0),
00075         m_timedLockPtr(0),
00076         m_referenceCount()
00077     {
00078       if(timeout < 0.0) {
00079         timeout = 0.0;
00080       }
00081       boost::xtime xtimeout;
00082       if(!getXTime(timeout, xtimeout)) {
00083         DLR_THROW(RunTimeException, "Token::Token()",
00084                   "Can't get current time.");
00085       }
00086       try {
00087         m_timedLockPtr =
00088           new boost::timed_mutex::scoped_timed_lock(mutex, xtimeout);
00089       } catch(boost::lock_error&) {
00090         // Leave m_timedLockPtr == 0
00091       }          
00092     }
00093 
00094 
00095     Token::
00096     ~Token() {
00097       if (!m_referenceCount.isShared()) {
00098         if(m_isTimed) {
00099           delete m_timedLockPtr;
00100         } else {
00101           delete m_lockPtr;
00102         }
00103       }
00104     }
00105 
00106 
00107     Token::
00108     operator bool()
00109     {
00110       return ((m_lockPtr != 0) || (m_timedLockPtr != 0));
00111     }
00112 
00113     
00114     boost::timed_mutex::scoped_lock&
00115     Token::
00116     getLock()
00117     {
00118       return *m_lockPtr;
00119     }
00120 
00121 
00122     boost::timed_mutex::scoped_timed_lock&
00123     Token::
00124     getTimedLock()
00125     {
00126       return *m_timedLockPtr;
00127     }
00128     
00129 
00130     bool
00131     Token::
00132     isTimed()
00133     {
00134       return m_isTimed;
00135     }
00136 
00137     
00138     Condition::
00139     Condition(boost::condition* conditionPtr)
00140       : m_conditionPtr(conditionPtr)
00141     {
00142       // Empty.
00143     }
00144 
00145 
00146     Condition::
00147     Condition(const Condition& other)
00148       : m_conditionPtr(other.m_conditionPtr)
00149     {
00150       // Empty.
00151     }
00152 
00153     
00154     Condition::
00155     ~Condition()
00156     {
00157       // Empty.
00158     }
00159 
00160 
00161     Condition&
00162     Condition::
00163     operator=(const Condition& other)
00164     {
00165       if(&other != this) {
00166         m_conditionPtr = other.m_conditionPtr;
00167       }
00168       return *this;
00169     }
00170 
00171     
00172     void
00173     Condition::
00174     signalOne()
00175     {
00176       if(m_conditionPtr != 0) {
00177         m_conditionPtr->notify_one();
00178       }
00179     }
00180 
00181     
00182     void
00183     Condition::
00184     signalAll()
00185     {
00186       if(m_conditionPtr != 0) {
00187         m_conditionPtr->notify_all();
00188       }
00189     }
00190 
00191     
00192     void
00193     Condition::
00194     wait(Token& token)
00195     {
00196       if(m_conditionPtr != 0) {
00197         if(token.isTimed()) {
00198           m_conditionPtr->wait(token.getTimedLock());
00199         } else {
00200           m_conditionPtr->wait(token.getLock());
00201         }
00202       }
00203     }
00204 
00205     
00206     bool
00207     Condition::
00208     wait(Token& token, double timeout)
00209     {
00210       if(m_conditionPtr != 0) {
00211         if(timeout < 0.0) {
00212           timeout = 0.0;
00213         }
00214         boost::xtime xtimeout;
00215         if(!getXTime(timeout, xtimeout)) {
00216           return false;
00217         }
00218         if(token.isTimed()) {
00219           return m_conditionPtr->timed_wait(token.getTimedLock(), xtimeout);
00220         }
00221         return m_conditionPtr->timed_wait(token.getLock(), xtimeout);
00222       }
00223       return false;
00224     }
00225 
00226 
00227     
00228     Monitor::
00229     Monitor()
00230       : m_tokenMutexPtr(new boost::timed_mutex),
00231         m_boostConditionVectorPtr(new std::vector<boost::condition*>),
00232         m_isCopyable(false),
00233         m_referenceCountPtr(new size_t)
00234     {
00235       *m_referenceCountPtr = 1;
00236     }
00237 
00238 
00239     // The copy constructor does a shallow copy.
00240     Monitor::
00241     Monitor(const Monitor& other)
00242       : m_tokenMutexPtr(0),
00243         m_boostConditionVectorPtr(0),
00244         m_isCopyable(false),
00245         m_referenceCountPtr(0)
00246     {
00247       this->copyOther(other);
00248     }
00249 
00250     
00251     // Destroys the Monitor instance and releases any resources.
00252     Monitor::
00253     ~Monitor()
00254     {
00255       this->releaseResources();
00256     }
00257 
00258     
00259     // The assignment operator does a shallow copy.
00260     Monitor&
00261     Monitor::
00262     operator=(const Monitor& other)
00263     {
00264       if(&other != this) {
00265         if(!m_isCopyable) {
00266           DLR_THROW(LogicException, "Monitor::operator=()",
00267                     "Attempt to copy a Monitor instance or subclass "
00268                     "without explicitly enabling copying.");
00269         }
00270         this->releaseResources();
00271         this->copyOther(other);
00272       }
00273       return *this;
00274     }      
00275 
00276 
00277     // This protected member function is called by the copy
00278     // constructor and assignment operator in order to copy another
00279     // Monitor instance in a thread-safe way.
00280     void
00281     Monitor::
00282     copyOther(const Monitor& other)
00283     {
00284       // m_tokenMutexPtr must be valid because we're copying a valid
00285       // Monitor instance.
00286       m_tokenMutexPtr = other.m_tokenMutexPtr;
00287       {
00288         Token token = this->getToken();
00289         if(!other.m_isCopyable) {
00290           DLR_THROW(LogicException, "Monitor::copyOther()",
00291                     "Attempt to copy a Monitor instance or subclass "
00292                     "without explicitly enabling copying.");
00293         }
00294         m_boostConditionVectorPtr = other.m_boostConditionVectorPtr;
00295         m_isCopyable = other.m_isCopyable;
00296         m_referenceCountPtr = other.m_referenceCountPtr;
00297         ++(*m_referenceCountPtr);
00298       }
00299     }
00300 
00301       
00302     // This protected member function creates a condition to be used
00303     // for communicating with other threads.
00304     Condition
00305     Monitor::
00306     createCondition(bool doInitialize)
00307     {
00308       if(doInitialize) {
00309         // When calling createCondition from within a constructor,
00310         // this next line works as long as m_tokenMutexPtr has already
00311         // been initialized.
00312         Token token = this->getToken();
00313         m_boostConditionVectorPtr->push_back(new boost::condition);
00314         size_t index0 = m_boostConditionVectorPtr->size() - 1;
00315         return Condition((*m_boostConditionVectorPtr)[index0]);
00316       }
00317       return Condition(0);
00318     }
00319 
00320 
00321     // This protected member function is called by the destructor
00322     // and assignment operator to decrement reference counts, etc.
00323     void
00324     Monitor::
00325     releaseResources()
00326     {
00327       bool isShared = true;
00328       {
00329         Token token = this->getToken();
00330         if(--(*m_referenceCountPtr) == 0) {
00331           isShared = false;
00332         }
00333       }
00334 
00335       if(!isShared) {
00336         // Since *this is the only copy left, we can go ahead
00337         // and delete.
00338         for(size_t index0 = 0; index0 < m_boostConditionVectorPtr->size();
00339             ++index0) {
00340           delete (*m_boostConditionVectorPtr)[index0];    
00341         }
00342         
00343         delete m_tokenMutexPtr;
00344         m_tokenMutexPtr = 0;
00345         delete m_boostConditionVectorPtr;
00346         m_boostConditionVectorPtr = 0;
00347         delete m_referenceCountPtr;
00348         m_referenceCountPtr = 0;
00349       }
00350     }
00351     
00352   } // namespace thread
00353 
00354 } // namespace dlr

Generated on Mon Jul 9 20:34:03 2007 for dlrLibs Utility Libraries by  doxygen 1.5.2