pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_Lock.h
00001 /*
00002  -------------------------------------------------------------------------------
00003  This file is part of the Plink, Plonk, Plank libraries
00004   by Martin Robinson
00005  
00006  http://code.google.com/p/pl-nk/
00007  
00008  Copyright University of the West of England, Bristol 2011-14
00009  All rights reserved.
00010  
00011  Redistribution and use in source and binary forms, with or without
00012  modification, are permitted provided that the following conditions are met:
00013  
00014  * Redistributions of source code must retain the above copyright
00015    notice, this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright
00017    notice, this list of conditions and the following disclaimer in the
00018    documentation and/or other materials provided with the distribution.
00019  * Neither the name of University of the West of England, Bristol nor 
00020    the names of its contributors may be used to endorse or promote products
00021    derived from this software without specific prior written permission.
00022  
00023  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00024  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00025  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00026  DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF THE WEST OF ENGLAND, BRISTOL BE 
00027  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
00028  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
00029  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
00030  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00031  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
00032  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00033  
00034  This software makes use of third party libraries. For more information see:
00035  doc/license.txt included in the distribution.
00036  -------------------------------------------------------------------------------
00037  */
00038 
00039 #ifndef PLONK_LOCK_H
00040 #define PLONK_LOCK_H
00041 
00042 #include "plonk_CoreForwardDeclarations.h"
00043 #include "plonk_SmartPointer.h"
00044 #include "plonk_WeakPointer.h"
00045 #include "plonk_SmartPointerContainer.h"
00046 
00047 class LockInternalBase : public SmartPointer
00048 {
00049 public:
00050     LockInternalBase() throw() : SmartPointer (false) { } // no weak ref needed
00051     ~LockInternalBase() { }
00052     
00053     virtual void lock() throw() = 0;
00054     virtual void unlock() throw() = 0;
00055     virtual bool tryLock() throw() = 0;
00056     virtual void wait (const double time) throw() = 0;
00057     virtual void signal() throw() = 0;
00058 
00059 };
00060 
00061 class NoLockInternal : public LockInternalBase
00062 {
00063 public:
00064     NoLockInternal() throw() { }
00065     ~NoLockInternal() { }
00066     
00067     void lock() throw() { }
00068     void unlock() throw() { }
00069     bool tryLock() throw() { return true; }
00070     void wait (const double time) throw() { (void)time; }
00071     void signal() throw() { }
00072     
00073 private:
00074 };
00075 
00076 class LockInternal : public LockInternalBase
00077 {
00078 public:
00079     LockInternal() throw();
00080     ~LockInternal();
00081     
00082     void lock() throw();
00083     void unlock() throw();
00084     bool tryLock() throw();
00085     void wait (const double time) throw();
00086     void signal() throw();
00087 
00088 private:
00089     inline PlankLockRef getPeerRef() { return &l; }
00090     PlankLock l;    
00091 };
00092 
00093 class SpinLockInternal : public LockInternalBase
00094 {
00095 public:
00096     SpinLockInternal() throw();
00097     ~SpinLockInternal();
00098     
00099     void lock() throw();
00100     void unlock() throw();
00101     bool tryLock() throw();
00102     void wait (const double time) throw();
00103     void signal() throw();
00104     
00105 private:
00106     inline PlankSpinLockRef getPeerRef() { return &l; }
00107     PlankSpinLock l;    
00108 };
00109 
00110 class ThreadSpinLockInternal : public LockInternalBase
00111 {
00112 public:
00113     ThreadSpinLockInternal() throw();
00114     ~ThreadSpinLockInternal();
00115     
00116     void lock() throw();
00117     void unlock() throw();
00118     bool tryLock() throw();
00119     void wait (const double time) throw();
00120     void signal() throw();
00121     
00122 private:
00123     inline PlankThreadSpinLockRef getPeerRef() { return &l; }
00124     PlankThreadSpinLock l;    
00125 };
00126 
00127 
00128 //------------------------------------------------------------------------------
00129 
00131 class Lock : public SmartPointerContainer<LockInternalBase>
00132 {
00133 public:
00134     typedef SmartPointerContainer<LockInternalBase> Base;
00135 
00136     enum Type
00137     {
00138         NoLock,             
00139         MutexLock,          
00140         SpinLock,           
00141         ThreadSpinLock,     
00142         NumTypes
00143     };
00144     
00145     Lock (const Lock::Type lockType = MutexLock) throw();
00146     
00147     explicit Lock (LockInternalBase* internalToUse) throw();
00148     
00150     Lock (Lock const& copy) throw();
00151     Lock& operator= (Lock const& other) throw();
00152     
00153     inline void lock() throw()                      { getInternal()->lock(); }
00154     inline void unlock() throw()                    { getInternal()->unlock(); }
00155     inline bool tryLock() throw()                   { return getInternal()->tryLock(); }
00156     inline void wait() throw()                      { getInternal()->wait (0.0); }
00157     inline void wait (const double time) throw()    { getInternal()->wait (time); }
00158     inline void signal() throw()                    { getInternal()->signal(); }
00159     
00160     PLONK_OBJECTARROWOPERATOR(Lock);
00161     
00162 private:
00163     static LockInternalBase* lockInternalFromType (const int lockType) throw();
00164 };
00165 
00166 //------------------------------------------------------------------------------
00167 
00169 class AutoLock
00170 {
00171 public:
00172     AutoLock (Lock const& lock = Lock::MutexLock) throw();
00173     ~AutoLock();
00174     
00175 private:
00176     Lock theLock;
00177     
00178     AutoLock (AutoLock const&);
00179     AutoLock& operator= (AutoLock const&);
00180 };
00181 
00182 //------------------------------------------------------------------------------
00183 
00185 class AutoUnlock
00186 {
00187 public:
00188     AutoUnlock (Lock const& lock = Lock::MutexLock) throw();
00189     ~AutoUnlock();
00190     
00191 private:
00192     Lock theLock;
00193     
00194     AutoUnlock (AutoUnlock const&);
00195     AutoUnlock& operator= (AutoUnlock const&);
00196 };
00197 
00198 //------------------------------------------------------------------------------
00199 
00201 class AutoTryLock
00202 {
00203 public:
00204     AutoTryLock (Lock const& lock = Lock::MutexLock, bool* didLock = 0) throw();
00205     ~AutoTryLock();
00206     
00207     bool getDidLock() const throw() { return didLock; }
00208         
00209 private:
00210     Lock theLock;
00211     bool didLock;
00212     
00213     AutoTryLock (AutoTryLock const&);
00214     AutoTryLock& operator= (AutoTryLock const&);
00215 };
00216 
00217 //------------------------------------------------------------------------------
00218 
00219 template<class ValueType>
00220 class LockedValueInternal : public SmartPointer
00221 {
00222 public:
00223     LockedValueInternal (ValueType const& initialValue, Lock const& lockToUse)
00224     :   value (initialValue),
00225         lock (lockToUse)
00226     {
00227     }
00228     
00229     void setValue (ValueType const& newValue) throw()
00230     {
00231         const AutoLock l (lock);
00232         value = newValue;
00233     }
00234     
00235     bool trySetValue (ValueType const& newValue) throw()
00236     {
00237         const AutoTryLock l (lock);
00238         
00239         if (l.getDidLock())
00240         {
00241             value = newValue;
00242             return true;
00243         }
00244         
00245         return false;
00246     }
00247     
00248     ValueType getValue() const throw()
00249     {
00250         ValueType tmp;
00251         
00252         const AutoLock l (lock);
00253         tmp = value;
00254         return tmp;
00255     }
00256     
00257     inline Lock& getLock() throw() { return lock; }
00258     
00259 private:
00260     ValueType value;
00261     Lock lock;
00262 };
00263 
00269 template<class Type>
00270 class LockedValue : public SmartPointerContainer< LockedValueInternal<Type> >
00271 {
00272 public:
00273     typedef LockedValueInternal<Type>             Internal;
00274     typedef SmartPointerContainer<Internal>       Base;
00275     typedef Type                                  ValueType;   
00276 
00277     LockedValue (Type const& value = Type(), 
00278                  Lock const& lock = Lock::SpinLock)
00279     :   Base (new Internal (value, lock))
00280     {
00281     }
00282     
00283     LockedValue (LockedValue const& copy) throw()
00284     :   Base (static_cast<Base> (copy))
00285     {
00286     }
00287     
00288     LockedValue& operator= (LockedValue const& other) throw()
00289     {
00290         if (this != &other)
00291             this->setInternal (other.getInternal());
00292         
00293         return *this;
00294     }
00295     
00296     inline LockedValue& operator= (Type const& other) throw()
00297     {
00298         this->setValue (other);
00299         return *this;
00300     }
00301     
00302     inline void setValue (Type const& newValue) throw()
00303     {
00304         this->getInternal()->setValue (newValue);
00305     }
00306     
00307     inline bool trySetValue (Type const& newValue) throw()
00308     {
00309         return this->getInternal()->trySetValue (newValue);
00310     }
00311     
00312     inline Type getValue() const throw()
00313     {
00314         return this->getInternal()->getValue();
00315     }
00316         
00317     inline operator Type() const throw()
00318     {
00319         return this->getInternal()->getValue();
00320     }
00321     
00322     PLONK_OBJECTARROWOPERATOR(LockedValue);
00323     
00324     template<typename Function>
00325     inline void operator() (VoidReturn::Type ret, Function function)
00326     {
00327         (void)ret;
00328         Type value = this->getValue();
00329         const AutoLock l (this->getInternal()->getLock());
00330         (value.*function)();
00331     }
00332 
00333     template<typename Function, class Arg1Type>
00334     inline void operator() (VoidReturn::Type ret, Function function, Arg1Type arg1)
00335     {
00336         (void)ret;
00337         Type value = this->getValue();
00338         const AutoLock l (this->getInternal()->getLock());
00339         (value.*function)(arg1);
00340     }
00341     
00342     template<typename Function, class Arg1Type, class Arg2Type>
00343     inline void operator() (VoidReturn::Type ret, Function function, Arg1Type arg1, Arg2Type arg2)
00344     {
00345         (void)ret;
00346         Type value = this->getValue();
00347         const AutoLock l (this->getInternal()->getLock());
00348         (value.*function)(arg1, arg2);
00349     }
00350 
00351     template<class ReturnType, typename Function, class Arg1Type, class Arg2Type, class Arg3Type>
00352     inline void operator() (VoidReturn::Type ret, Function function, Arg1Type arg1, Arg2Type arg2, Arg3Type arg3)
00353     {
00354         (void)ret;
00355         Type value = this->getValue();
00356         const AutoLock l (this->getInternal()->getLock());
00357         (value.*function)(arg1, arg2, arg3);
00358     }
00359     
00360     template<class ReturnType, typename Function>
00361     inline void operator() (ReturnType* ret, Function function)
00362     {
00363         Type value = this->getValue();
00364         
00365         if (ret)
00366         {
00367             const AutoLock l (this->getInternal()->getLock());
00368             *ret = (value.*function)();
00369         }
00370         else
00371         {
00372             (*this)(VoidReturn::Pass, function);
00373         }   
00374     }
00375 
00376     template<class ReturnType, typename Function, class Arg1Type>
00377     inline void operator() (ReturnType* ret, Function function, Arg1Type arg1)
00378     {
00379         Type value = this->getValue();
00380 
00381         if (ret)
00382         {
00383             const AutoLock l (this->getInternal()->getLock());
00384             *ret = (value.*function)(arg1);
00385         }
00386         else
00387         {
00388             (*this)(VoidReturn::Pass, function, arg1);
00389         }   
00390     }
00391     
00392     template<class ReturnType, typename Function, class Arg1Type, class Arg2Type>
00393     inline void operator() (ReturnType* ret, Function function, Arg1Type arg1, Arg2Type arg2)
00394     {
00395         Type value = this->getValue();
00396 
00397         if (ret)
00398         {
00399             const AutoLock l (this->getInternal()->getLock());
00400             *ret = (value.*function)(arg1, arg2);
00401         }
00402         else
00403         {
00404             (*this)(VoidReturn::Pass, function, arg1, arg2);
00405         }   
00406     }
00407     
00408     template<class ReturnType, typename Function, class Arg1Type, class Arg2Type, class Arg3Type>
00409     inline void operator() (ReturnType* ret, Function function, Arg1Type arg1, Arg2Type arg2, Arg3Type arg3)
00410     {
00411         Type value = this->getValue();
00412 
00413         if (ret)
00414         {
00415             const AutoLock l (this->getInternal()->getLock());
00416             *ret = (value.*function)(arg1, arg2, arg3);
00417         }
00418         else
00419         {
00420             (*this)(VoidReturn::Pass, function, arg1, arg2, arg3);
00421         }   
00422     }
00423     
00424     inline Lock& getLock() throw() { return this->getInternal()->getLock(); }
00425     
00426     inline void lock() throw() { this->getLock().lock(); } 
00427     inline void unlock() throw() { this->getLock().unlock(); } 
00428     inline bool tryLock() throw() { return this->getLock().tryLock(); } 
00429 
00430 };
00431 
00432 #define PLONK_LOCKEDVALUE_CALL(VALUETYPE, LOCKEDVALUE, FUNCTION, ARGS) \
00433     do {\
00434         VALUETYPE value = LOCKEDVALUE.getValue();\
00435         const AutoLock l (LOCKEDVALUE.getLock());\
00436         value.FUNCTION ARGS;\
00437     } while (false);\
00438 
00439 #define PLONK_LOCKEDVALUE_CALLRETURN(VALUETYPE, RETURNEXPR, LOCKEDVALUE, FUNCTION, ARGS) \
00440     do {\
00441         VALUETYPE value = LOCKEDVALUE.getValue();\
00442         const AutoLock l (LOCKEDVALUE.getLock());\
00443         RETURNEXPR value.FUNCTION ARGS;\
00444     } while (false);\
00445 
00446 
00447 #endif // PLONK_LOCK_H
 All Classes Functions Typedefs Enumerations Enumerator Properties