safecoll.h

Go to the documentation of this file.
00001 /*
00002  * safecoll.h
00003  *
00004  * Thread safe collection classes.
00005  *
00006  * Portable Windows Library
00007  *
00008  * Copyright (c) 2002 Equivalence Pty. Ltd.
00009  *
00010  * The contents of this file are subject to the Mozilla Public License
00011  * Version 1.0 (the "License"); you may not use this file except in
00012  * compliance with the License. You may obtain a copy of the License at
00013  * http://www.mozilla.org/MPL/
00014  *
00015  * Software distributed under the License is distributed on an "AS IS"
00016  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00017  * the License for the specific language governing rights and limitations
00018  * under the License.
00019  *
00020  * The Original Code is Portable Windows Library.
00021  *
00022  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
00023  *
00024  * Contributor(s): ______________________________________.
00025  *
00026  * $Log: safecoll.h,v $
00027  * Revision 1.15.2.1  2007/05/09 11:54:15  csoutheren
00028  * Backport from head
00029  *
00030  * Revision 1.16  2007/04/20 02:31:14  rjongbloed
00031  * Added ability to share a single mutex amongst multiple PSafeObjects,
00032  *   this can help with certain deadlock scenarios.
00033  *
00034  * Revision 1.15  2005/11/25 03:43:47  csoutheren
00035  * Fixed function argument comments to be compatible with Doxygen
00036  *
00037  * Revision 1.14  2004/11/08 02:34:18  csoutheren
00038  * Refactored code to (hopefully) compile on Linux
00039  *
00040  * Revision 1.13  2004/11/07 12:55:38  rjongbloed
00041  * Fixed safe ptr casting so keeps associated collection for use in for loops.
00042  *
00043  * Revision 1.12  2004/10/28 12:19:44  rjongbloed
00044  * Added oeprator! to assure test for NULL that some people use is correct for PSafePtr
00045  *
00046  * Revision 1.11  2004/10/14 12:31:45  rjongbloed
00047  * Added synchronous mode for safe collection RemoveAll() to wait until all objects
00048  *   have actually been deleted before returning.
00049  *
00050  * Revision 1.10  2004/10/04 12:54:33  rjongbloed
00051  * Added functions for locking an unlocking to "auto-unlock" classes.
00052  *
00053  * Revision 1.9  2004/08/12 12:37:40  rjongbloed
00054  * Fixed bug recently introduced so removes deleted object from deletion list.
00055  * Also changed removal list to be correct type.
00056  *
00057  * Revision 1.8  2004/08/05 12:15:56  rjongbloed
00058  * Added classes for auto unlocking read only and read write mutex on
00059  *   PSafeObject - similar to PWaitAndSIgnal.
00060  * Utilised mutable keyword for mutex and improved the constness of functions.
00061  * Added DisallowDeleteObjects to safe collections so can have a PSafeObject in
00062  *   multiple collections.
00063  * Added a tempalte function to do casting of PSafePtr to a PSafePtr of a derived
00064  *   class.
00065  * Assured that a PSafeObject present on a collection always increments its
00066  *   reference count so while in collection it is not deleted.
00067  *
00068  * Revision 1.7  2002/12/10 07:36:57  robertj
00069  * Fixed possible deadlock in PSafeCollection find functions.
00070  *
00071  * Revision 1.6  2002/10/29 00:06:14  robertj
00072  * Changed template classes so things like PSafeList actually creates the
00073  *   base collection class as well.
00074  * Allowed for the PSafeList::Append() to return a locked pointer to the
00075  *   object just appended.
00076  *
00077  * Revision 1.5  2002/10/04 08:22:40  robertj
00078  * Changed read/write mutex so can be called by same thread without deadlock
00079  *   removing the need to a lock count in safe pointer.
00080  * Added asserts if try and dereference a NULL safe pointer.
00081  * Added more documentation on behaviour.
00082  *
00083  * Revision 1.4  2002/09/16 01:08:59  robertj
00084  * Added #define so can select if #pragma interface/implementation is used on
00085  *   platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan.
00086  *
00087  * Revision 1.3  2002/08/29 06:51:11  robertj
00088  * Added optimisiation, separate mutex for toBeRemoved list.
00089  *
00090  * Revision 1.2  2002/05/06 00:44:45  robertj
00091  * Made the lock/unlock read only const so can be used in const functions.
00092  *
00093  * Revision 1.1  2002/05/01 04:16:43  robertj
00094  * Added thread safe collection classes.
00095  *
00096  */
00097  
00098 #ifndef _SAFE_COLLECTION_H
00099 #define _SAFE_COLLECTION_H
00100 
00101 #ifdef P_USE_PRAGMA
00102 #pragma interface
00103 #endif
00104 
00105 
00164 class PSafeObject : public PObject
00165 {
00166     PCLASSINFO(PSafeObject, PObject);
00167   public:
00172     PSafeObject(
00173         PSafeObject * indirectLock = NULL 
00174     );
00176 
00197     BOOL SafeReference();
00198 
00206     void SafeDereference();
00207 
00225     BOOL LockReadOnly() const;
00226 
00237     void UnlockReadOnly() const;
00238 
00256     BOOL LockReadWrite();
00257 
00268     void UnlockReadWrite();
00269 
00279     void SafeRemove();
00280 
00288     BOOL SafelyCanBeDeleted() const;
00290 
00291   private:
00292     mutable PMutex    safetyMutex;
00293     unsigned          safeReferenceCount;
00294     BOOL              safelyBeingRemoved;
00295     PReadWriteMutex   safeInUseMutex;
00296     PReadWriteMutex * safeInUse;
00297 };
00298 
00299 
00302 class PSafeLockReadOnly
00303 {
00304   public:
00305     PSafeLockReadOnly(const PSafeObject & object);
00306     ~PSafeLockReadOnly();
00307     BOOL Lock();
00308     void Unlock();
00309     BOOL IsLocked() const { return locked; }
00310     bool operator!() const { return !locked; }
00311 
00312   protected:
00313     PSafeObject & safeObject;
00314     BOOL          locked;
00315 };
00316 
00317 
00318 
00321 class PSafeLockReadWrite
00322 {
00323   public:
00324     PSafeLockReadWrite(const PSafeObject & object);
00325     ~PSafeLockReadWrite();
00326     BOOL Lock();
00327     void Unlock();
00328     BOOL IsLocked() const { return locked; }
00329     bool operator!() const { return !locked; }
00330 
00331   protected:
00332     PSafeObject & safeObject;
00333     BOOL          locked;
00334 };
00335 
00336 
00337 
00350 class PSafeCollection : public PObject
00351 {
00352     PCLASSINFO(PSafeCollection, PObject);
00353   public:
00359     PSafeCollection(
00360       PCollection * collection    
00361      );
00362 
00366     ~PSafeCollection();
00368 
00371   protected:
00380     virtual BOOL SafeRemove(
00381       PSafeObject * obj   
00382     );
00383 
00392     virtual BOOL SafeRemoveAt(
00393       PINDEX idx    
00394     );
00395 
00396   public:
00399     virtual void RemoveAll(
00400       BOOL synchronous = FALSE  
00401     );
00402 
00407     void AllowDeleteObjects(
00408       BOOL yes = TRUE   
00409     ) { deleteObjects = yes; }
00410 
00415     void DisallowDeleteObjects() { deleteObjects = FALSE; }
00416 
00421     virtual BOOL DeleteObjectsToBeRemoved();
00422 
00425     virtual void DeleteObject(PObject * object) const;
00426 
00429     virtual void SetAutoDeleteObjects();
00430 
00435     PINDEX GetSize() const;
00436 
00441     BOOL IsEmpty() const { return GetSize() == 0; }
00442 
00445     const PMutex & GetMutex() const { return collectionMutex; }
00447 
00448   protected:
00449     void SafeRemoveObject(PSafeObject * obj);
00450     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00451 
00452     PCollection  *     collection;
00453     mutable PMutex     collectionMutex;
00454     BOOL               deleteObjects;
00455     PList<PSafeObject> toBeRemoved;
00456     PMutex             removalMutex;
00457     PTimer             deleteObjectsTimer;
00458 
00459   friend class PSafePtrBase;
00460 };
00461 
00462 
00463 enum PSafetyMode {
00464   PSafeReference,
00465   PSafeReadOnly,
00466   PSafeReadWrite
00467 };
00468 
00484 class PSafePtrBase : public PObject
00485 {
00486     PCLASSINFO(PSafePtrBase, PObject);
00487 
00490   protected:
00498     PSafePtrBase(
00499       PSafeObject * obj = NULL,         
00500       PSafetyMode mode = PSafeReference 
00501     );
00502 
00510     PSafePtrBase(
00511       const PSafeCollection & safeCollection, 
00512       PSafetyMode mode,                       
00513       PINDEX idx                              
00514     );
00515 
00523     PSafePtrBase(
00524       const PSafeCollection & safeCollection, 
00525       PSafetyMode mode,                       
00526       PSafeObject * obj                       
00527     );
00528 
00534     PSafePtrBase(
00535       const PSafePtrBase & enumerator   
00536     );
00537 
00538   public:
00541     ~PSafePtrBase();
00543 
00550     Comparison Compare(
00551       const PObject & obj   
00552     ) const;
00554 
00559     bool operator!() const { return currentObject == NULL; }
00560 
00563     PSafetyMode GetSafetyMode() const { return lockMode; }
00564 
00567     BOOL SetSafetyMode(
00568       PSafetyMode mode  
00569     );
00570 
00573     const PSafeCollection * GetCollection() const { return collection; }
00575 
00576     void Assign(const PSafePtrBase & ptr);
00577     void Assign(const PSafeCollection & safeCollection);
00578     void Assign(PSafeObject * obj);
00579     void Assign(PINDEX idx);
00580 
00581   protected:
00582     void Next();
00583     void Previous();
00584 
00585     enum EnterSafetyModeOption {
00586       WithReference,
00587       AlreadyReferenced
00588     };
00589     BOOL EnterSafetyMode(EnterSafetyModeOption ref);
00590 
00591     enum ExitSafetyModeOption {
00592       WithDereference,
00593       NoDereference
00594     };
00595     void ExitSafetyMode(ExitSafetyModeOption ref);
00596 
00597   protected:
00598     const PSafeCollection * collection;
00599     PSafeObject           * currentObject;
00600     PSafetyMode             lockMode;
00601 };
00602 
00603 
00625 template <class T> class PSafePtr : public PSafePtrBase
00626 {
00627     PCLASSINFO(PSafePtr, PSafePtrBase);
00628   public:
00638     PSafePtr(
00639       T * obj = NULL,                   
00640       PSafetyMode mode = PSafeReference 
00641     ) : PSafePtrBase(obj, mode) { }
00642 
00650     PSafePtr(
00651       const PSafeCollection & safeCollection, 
00652       PSafetyMode mode = PSafeReadWrite,      
00653       PINDEX idx = 0                          
00654     ) : PSafePtrBase(safeCollection, mode, idx) { }
00655 
00663     PSafePtr(
00664       const PSafeCollection & safeCollection, 
00665       PSafetyMode mode,                       
00666       PSafeObject * obj                       
00667     ) : PSafePtrBase(safeCollection, mode, obj) { }
00668 
00674     PSafePtr(
00675       const PSafePtr & ptr   
00676     ) : PSafePtrBase(ptr) { }
00677 
00683     PSafePtr & operator=(const PSafePtr & ptr)
00684       {
00685         Assign(ptr);
00686         return *this;
00687       }
00688 
00693     PSafePtr & operator=(const PSafeCollection & safeCollection)
00694       {
00695         Assign(safeCollection);
00696         return *this;
00697       }
00698 
00714     PSafePtr & operator=(T * obj)
00715       {
00716         Assign(obj);
00717         return *this;
00718       }
00719 
00729     PSafePtr & operator=(PINDEX idx)
00730       {
00731         Assign(idx);
00732         return *this;
00733       }
00735 
00740     operator T*()    const { return  (T *)currentObject; }
00741 
00744     T & operator*()  const { return *(T *)PAssertNULL(currentObject); }
00745 
00748     T * operator->() const { return  (T *)PAssertNULL(currentObject); }
00749 
00754     T * operator++(int)
00755       {
00756         T * previous = (T *)currentObject;
00757         Next();
00758         return previous;
00759       }
00760 
00765     T * operator++()
00766       {
00767         Next();
00768         return (T *)currentObject;
00769       }
00770 
00775     T * operator--(int)
00776       {
00777         T * previous = (T *)currentObject;
00778         Previous();
00779         return previous;
00780       }
00781 
00786     T * operator--()
00787       {
00788         Previous();
00789         return (T *)currentObject;
00790       }
00792 
00796       /*
00797   template <class Base>
00798   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00799   {
00800     PSafePtr<T> newPtr;
00801     Base * realPtr = oldPtr;
00802     if (realPtr != NULL && PIsDescendant(realPtr, T))
00803       newPtr.Assign(oldPtr);
00804     return newPtr;
00805   }
00806   */
00807 };
00808 
00809 
00813 template <class Base, class Derived>
00814 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00815 {
00816 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00817     PSafePtr<Derived> newPtr;
00818     Base * realPtr = oldPtr;
00819     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00820       newPtr.Assign(oldPtr);
00821     return newPtr;
00822 }
00823 
00824 
00835 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00836 {
00837     PCLASSINFO(PSafeColl, PSafeCollection);
00838   public:
00843     PSafeColl()
00844       : PSafeCollection(new Coll)
00845       { }
00847 
00854     virtual PSafePtr<Base> Append(
00855       Base * obj,       
00856       PSafetyMode mode = PSafeReference
00857     ) {
00858         PWaitAndSignal mutex(collectionMutex);
00859         if (!obj->SafeReference())
00860           return NULL;
00861         return PSafePtr<Base>(*this, mode, collection->Append(obj));
00862       }
00863 
00872     virtual BOOL Remove(
00873       Base * obj          
00874     ) {
00875         return SafeRemove(obj);
00876       }
00877 
00886     virtual BOOL RemoveAt(
00887       PINDEX idx     
00888     ) {
00889         return SafeRemoveAt(idx);
00890       }
00891 
00897     virtual PSafePtr<Base> GetAt(
00898       PINDEX idx,
00899       PSafetyMode mode = PSafeReadWrite
00900     ) {
00901         return PSafePtr<Base>(*this, mode, idx);
00902       }
00903 
00909     virtual PSafePtr<Base> FindWithLock(
00910       const Base & value,
00911       PSafetyMode mode = PSafeReadWrite
00912     ) {
00913         collectionMutex.Wait();
00914         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00915         collectionMutex.Signal();
00916         ptr.SetSafetyMode(mode);
00917         return ptr;
00918       }
00920 };
00921 
00922 
00927 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00928 {
00929 };
00930 
00931 
00936 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
00937 {
00938 };
00939 
00940 
00945 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
00946 {
00947 };
00948 
00949 
00960 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
00961 {
00962     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
00963   public:
00968     PSafeDictionaryBase()
00969       : PSafeCollection(new Coll) { }
00971 
00978     virtual void SetAt(const Key & key, Base * obj)
00979       {
00980         collectionMutex.Wait();
00981         SafeRemove(((Coll *)collection)->GetAt(key));
00982         if (obj->SafeReference())
00983           ((Coll *)collection)->SetAt(key, obj);
00984         collectionMutex.Signal();
00985       }
00986 
00995     virtual BOOL RemoveAt(
00996       const Key & key   
00997     ) {
00998         PWaitAndSignal mutex(collectionMutex);
00999         return SafeRemove(((Coll *)collection)->GetAt(key));
01000       }
01001 
01004     virtual BOOL Contains(
01005       const Key & key
01006     ) {
01007         PWaitAndSignal lock(collectionMutex);
01008         return ((Coll *)collection)->Contains(key);
01009       }
01010 
01016     virtual PSafePtr<Base> GetAt(
01017       PINDEX idx,
01018       PSafetyMode mode = PSafeReadWrite
01019     ) {
01020         return PSafePtr<Base>(*this, mode, idx);
01021       }
01022 
01028     virtual PSafePtr<Base> FindWithLock(
01029       const Key & key,
01030       PSafetyMode mode = PSafeReadWrite
01031     ) {
01032         collectionMutex.Wait();
01033         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01034         collectionMutex.Signal();
01035         ptr.SetSafetyMode(mode);
01036         return ptr;
01037       }
01039 };
01040 
01041 
01046 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01047 {
01048 };
01049 
01050 
01051 #endif // _SAFE_COLLECTION_H
01052 
01053 

Generated on Fri Sep 21 14:40:11 2007 for PWLib by  doxygen 1.5.3