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.17  2007/06/09 05:43:55  rjongbloed
00028  * Added ability for PSafePtr to be used as an garbage collecting pointer when not
00029  *   contained within a collection. Last PSafePtr reference to go out of scope deletes
00030  *   the object, provided it has never been in a PSafeCollection.
00031  *
00032  * Revision 1.16  2007/04/20 02:31:14  rjongbloed
00033  * Added ability to share a single mutex amongst multiple PSafeObjects,
00034  *   this can help with certain deadlock scenarios.
00035  *
00036  * Revision 1.15  2005/11/25 03:43:47  csoutheren
00037  * Fixed function argument comments to be compatible with Doxygen
00038  *
00039  * Revision 1.14  2004/11/08 02:34:18  csoutheren
00040  * Refactored code to (hopefully) compile on Linux
00041  *
00042  * Revision 1.13  2004/11/07 12:55:38  rjongbloed
00043  * Fixed safe ptr casting so keeps associated collection for use in for loops.
00044  *
00045  * Revision 1.12  2004/10/28 12:19:44  rjongbloed
00046  * Added oeprator! to assure test for NULL that some people use is correct for PSafePtr
00047  *
00048  * Revision 1.11  2004/10/14 12:31:45  rjongbloed
00049  * Added synchronous mode for safe collection RemoveAll() to wait until all objects
00050  *   have actually been deleted before returning.
00051  *
00052  * Revision 1.10  2004/10/04 12:54:33  rjongbloed
00053  * Added functions for locking an unlocking to "auto-unlock" classes.
00054  *
00055  * Revision 1.9  2004/08/12 12:37:40  rjongbloed
00056  * Fixed bug recently introduced so removes deleted object from deletion list.
00057  * Also changed removal list to be correct type.
00058  *
00059  * Revision 1.8  2004/08/05 12:15:56  rjongbloed
00060  * Added classes for auto unlocking read only and read write mutex on
00061  *   PSafeObject - similar to PWaitAndSIgnal.
00062  * Utilised mutable keyword for mutex and improved the constness of functions.
00063  * Added DisallowDeleteObjects to safe collections so can have a PSafeObject in
00064  *   multiple collections.
00065  * Added a tempalte function to do casting of PSafePtr to a PSafePtr of a derived
00066  *   class.
00067  * Assured that a PSafeObject present on a collection always increments its
00068  *   reference count so while in collection it is not deleted.
00069  *
00070  * Revision 1.7  2002/12/10 07:36:57  robertj
00071  * Fixed possible deadlock in PSafeCollection find functions.
00072  *
00073  * Revision 1.6  2002/10/29 00:06:14  robertj
00074  * Changed template classes so things like PSafeList actually creates the
00075  *   base collection class as well.
00076  * Allowed for the PSafeList::Append() to return a locked pointer to the
00077  *   object just appended.
00078  *
00079  * Revision 1.5  2002/10/04 08:22:40  robertj
00080  * Changed read/write mutex so can be called by same thread without deadlock
00081  *   removing the need to a lock count in safe pointer.
00082  * Added asserts if try and dereference a NULL safe pointer.
00083  * Added more documentation on behaviour.
00084  *
00085  * Revision 1.4  2002/09/16 01:08:59  robertj
00086  * Added #define so can select if #pragma interface/implementation is used on
00087  *   platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan.
00088  *
00089  * Revision 1.3  2002/08/29 06:51:11  robertj
00090  * Added optimisiation, separate mutex for toBeRemoved list.
00091  *
00092  * Revision 1.2  2002/05/06 00:44:45  robertj
00093  * Made the lock/unlock read only const so can be used in const functions.
00094  *
00095  * Revision 1.1  2002/05/01 04:16:43  robertj
00096  * Added thread safe collection classes.
00097  *
00098  */
00099  
00100 #ifndef _SAFE_COLLECTION_H
00101 #define _SAFE_COLLECTION_H
00102 
00103 #ifdef P_USE_PRAGMA
00104 #pragma interface
00105 #endif
00106 
00107 
00166 class PSafeObject : public PObject
00167 {
00168     PCLASSINFO(PSafeObject, PObject);
00169   public:
00174     PSafeObject(
00175         PSafeObject * indirectLock = NULL 
00176     );
00178 
00199     BOOL SafeReference();
00200 
00211     BOOL SafeDereference();
00212 
00230     BOOL LockReadOnly() const;
00231 
00242     void UnlockReadOnly() const;
00243 
00261     BOOL LockReadWrite();
00262 
00273     void UnlockReadWrite();
00274 
00284     void SafeRemove();
00285 
00293     BOOL SafelyCanBeDeleted() const;
00295 
00296   private:
00297     mutable PMutex    safetyMutex;
00298     unsigned          safeReferenceCount;
00299     BOOL              safelyBeingRemoved;
00300     PReadWriteMutex   safeInUseMutex;
00301     PReadWriteMutex * safeInUse;
00302 };
00303 
00304 
00307 class PSafeLockReadOnly
00308 {
00309   public:
00310     PSafeLockReadOnly(const PSafeObject & object);
00311     ~PSafeLockReadOnly();
00312     BOOL Lock();
00313     void Unlock();
00314     BOOL IsLocked() const { return locked; }
00315     bool operator!() const { return !locked; }
00316 
00317   protected:
00318     PSafeObject & safeObject;
00319     BOOL          locked;
00320 };
00321 
00322 
00323 
00326 class PSafeLockReadWrite
00327 {
00328   public:
00329     PSafeLockReadWrite(const PSafeObject & object);
00330     ~PSafeLockReadWrite();
00331     BOOL Lock();
00332     void Unlock();
00333     BOOL IsLocked() const { return locked; }
00334     bool operator!() const { return !locked; }
00335 
00336   protected:
00337     PSafeObject & safeObject;
00338     BOOL          locked;
00339 };
00340 
00341 
00342 
00355 class PSafeCollection : public PObject
00356 {
00357     PCLASSINFO(PSafeCollection, PObject);
00358   public:
00364     PSafeCollection(
00365       PCollection * collection    
00366      );
00367 
00371     ~PSafeCollection();
00373 
00376   protected:
00385     virtual BOOL SafeRemove(
00386       PSafeObject * obj   
00387     );
00388 
00397     virtual BOOL SafeRemoveAt(
00398       PINDEX idx    
00399     );
00400 
00401   public:
00404     virtual void RemoveAll(
00405       BOOL synchronous = FALSE  
00406     );
00407 
00412     void AllowDeleteObjects(
00413       BOOL yes = TRUE   
00414     ) { deleteObjects = yes; }
00415 
00420     void DisallowDeleteObjects() { deleteObjects = FALSE; }
00421 
00426     virtual BOOL DeleteObjectsToBeRemoved();
00427 
00430     virtual void DeleteObject(PObject * object) const;
00431 
00434     virtual void SetAutoDeleteObjects();
00435 
00440     PINDEX GetSize() const;
00441 
00446     BOOL IsEmpty() const { return GetSize() == 0; }
00447 
00450     const PMutex & GetMutex() const { return collectionMutex; }
00452 
00453   protected:
00454     void SafeRemoveObject(PSafeObject * obj);
00455     PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
00456 
00457     PCollection  *     collection;
00458     mutable PMutex     collectionMutex;
00459     BOOL               deleteObjects;
00460     PList<PSafeObject> toBeRemoved;
00461     PMutex             removalMutex;
00462     PTimer             deleteObjectsTimer;
00463 
00464   friend class PSafePtrBase;
00465 };
00466 
00467 
00468 enum PSafetyMode {
00469   PSafeReference,
00470   PSafeReadOnly,
00471   PSafeReadWrite
00472 };
00473 
00489 class PSafePtrBase : public PObject
00490 {
00491     PCLASSINFO(PSafePtrBase, PObject);
00492 
00495   protected:
00503     PSafePtrBase(
00504       PSafeObject * obj = NULL,         
00505       PSafetyMode mode = PSafeReference 
00506     );
00507 
00515     PSafePtrBase(
00516       const PSafeCollection & safeCollection, 
00517       PSafetyMode mode,                       
00518       PINDEX idx                              
00519     );
00520 
00528     PSafePtrBase(
00529       const PSafeCollection & safeCollection, 
00530       PSafetyMode mode,                       
00531       PSafeObject * obj                       
00532     );
00533 
00539     PSafePtrBase(
00540       const PSafePtrBase & enumerator   
00541     );
00542 
00543   public:
00546     ~PSafePtrBase();
00548 
00555     Comparison Compare(
00556       const PObject & obj   
00557     ) const;
00559 
00564     bool operator!() const { return currentObject == NULL; }
00565 
00568     PSafetyMode GetSafetyMode() const { return lockMode; }
00569 
00572     BOOL SetSafetyMode(
00573       PSafetyMode mode  
00574     );
00575 
00578     const PSafeCollection * GetCollection() const { return collection; }
00580 
00581     void Assign(const PSafePtrBase & ptr);
00582     void Assign(const PSafeCollection & safeCollection);
00583     void Assign(PSafeObject * obj);
00584     void Assign(PINDEX idx);
00585 
00586   protected:
00587     void Next();
00588     void Previous();
00589 
00590     enum EnterSafetyModeOption {
00591       WithReference,
00592       AlreadyReferenced
00593     };
00594     BOOL EnterSafetyMode(EnterSafetyModeOption ref);
00595 
00596     enum ExitSafetyModeOption {
00597       WithDereference,
00598       NoDereference
00599     };
00600     void ExitSafetyMode(ExitSafetyModeOption ref);
00601 
00602   protected:
00603     const PSafeCollection * collection;
00604     PSafeObject           * currentObject;
00605     PSafetyMode             lockMode;
00606 };
00607 
00608 
00630 template <class T> class PSafePtr : public PSafePtrBase
00631 {
00632     PCLASSINFO(PSafePtr, PSafePtrBase);
00633   public:
00643     PSafePtr(
00644       T * obj = NULL,                   
00645       PSafetyMode mode = PSafeReference 
00646     ) : PSafePtrBase(obj, mode) { }
00647 
00655     PSafePtr(
00656       const PSafeCollection & safeCollection, 
00657       PSafetyMode mode = PSafeReadWrite,      
00658       PINDEX idx = 0                          
00659     ) : PSafePtrBase(safeCollection, mode, idx) { }
00660 
00668     PSafePtr(
00669       const PSafeCollection & safeCollection, 
00670       PSafetyMode mode,                       
00671       PSafeObject * obj                       
00672     ) : PSafePtrBase(safeCollection, mode, obj) { }
00673 
00679     PSafePtr(
00680       const PSafePtr & ptr   
00681     ) : PSafePtrBase(ptr) { }
00682 
00688     PSafePtr & operator=(const PSafePtr & ptr)
00689       {
00690         Assign(ptr);
00691         return *this;
00692       }
00693 
00698     PSafePtr & operator=(const PSafeCollection & safeCollection)
00699       {
00700         Assign(safeCollection);
00701         return *this;
00702       }
00703 
00719     PSafePtr & operator=(T * obj)
00720       {
00721         Assign(obj);
00722         return *this;
00723       }
00724 
00734     PSafePtr & operator=(PINDEX idx)
00735       {
00736         Assign(idx);
00737         return *this;
00738       }
00740 
00745     operator T*()    const { return  (T *)currentObject; }
00746 
00749     T & operator*()  const { return *(T *)PAssertNULL(currentObject); }
00750 
00753     T * operator->() const { return  (T *)PAssertNULL(currentObject); }
00754 
00759     T * operator++(int)
00760       {
00761         T * previous = (T *)currentObject;
00762         Next();
00763         return previous;
00764       }
00765 
00770     T * operator++()
00771       {
00772         Next();
00773         return (T *)currentObject;
00774       }
00775 
00780     T * operator--(int)
00781       {
00782         T * previous = (T *)currentObject;
00783         Previous();
00784         return previous;
00785       }
00786 
00791     T * operator--()
00792       {
00793         Previous();
00794         return (T *)currentObject;
00795       }
00797 
00801       /*
00802   template <class Base>
00803   static PSafePtr<T> DownCast(const PSafePtr<Base> & oldPtr)
00804   {
00805     PSafePtr<T> newPtr;
00806     Base * realPtr = oldPtr;
00807     if (realPtr != NULL && PIsDescendant(realPtr, T))
00808       newPtr.Assign(oldPtr);
00809     return newPtr;
00810   }
00811   */
00812 };
00813 
00814 
00818 template <class Base, class Derived>
00819 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
00820 {
00821 //  return PSafePtr<Derived>::DownCast<Base>(oldPtr);
00822     PSafePtr<Derived> newPtr;
00823     Base * realPtr = oldPtr;
00824     if (realPtr != NULL && PIsDescendant(realPtr, Derived))
00825       newPtr.Assign(oldPtr);
00826     return newPtr;
00827 }
00828 
00829 
00840 template <class Coll, class Base> class PSafeColl : public PSafeCollection
00841 {
00842     PCLASSINFO(PSafeColl, PSafeCollection);
00843   public:
00848     PSafeColl()
00849       : PSafeCollection(new Coll)
00850       { }
00852 
00859     virtual PSafePtr<Base> Append(
00860       Base * obj,       
00861       PSafetyMode mode = PSafeReference
00862     ) {
00863         PWaitAndSignal mutex(collectionMutex);
00864         if (!obj->SafeReference())
00865           return NULL;
00866         return PSafePtr<Base>(*this, mode, collection->Append(obj));
00867       }
00868 
00877     virtual BOOL Remove(
00878       Base * obj          
00879     ) {
00880         return SafeRemove(obj);
00881       }
00882 
00891     virtual BOOL RemoveAt(
00892       PINDEX idx     
00893     ) {
00894         return SafeRemoveAt(idx);
00895       }
00896 
00902     virtual PSafePtr<Base> GetAt(
00903       PINDEX idx,
00904       PSafetyMode mode = PSafeReadWrite
00905     ) {
00906         return PSafePtr<Base>(*this, mode, idx);
00907       }
00908 
00914     virtual PSafePtr<Base> FindWithLock(
00915       const Base & value,
00916       PSafetyMode mode = PSafeReadWrite
00917     ) {
00918         collectionMutex.Wait();
00919         PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
00920         collectionMutex.Signal();
00921         ptr.SetSafetyMode(mode);
00922         return ptr;
00923       }
00925 };
00926 
00927 
00932 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
00933 {
00934 };
00935 
00936 
00941 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
00942 {
00943 };
00944 
00945 
00950 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
00951 {
00952 };
00953 
00954 
00965 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
00966 {
00967     PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
00968   public:
00973     PSafeDictionaryBase()
00974       : PSafeCollection(new Coll) { }
00976 
00983     virtual void SetAt(const Key & key, Base * obj)
00984       {
00985         collectionMutex.Wait();
00986         SafeRemove(((Coll *)collection)->GetAt(key));
00987         if (obj->SafeReference())
00988           ((Coll *)collection)->SetAt(key, obj);
00989         collectionMutex.Signal();
00990       }
00991 
01000     virtual BOOL RemoveAt(
01001       const Key & key   
01002     ) {
01003         PWaitAndSignal mutex(collectionMutex);
01004         return SafeRemove(((Coll *)collection)->GetAt(key));
01005       }
01006 
01009     virtual BOOL Contains(
01010       const Key & key
01011     ) {
01012         PWaitAndSignal lock(collectionMutex);
01013         return ((Coll *)collection)->Contains(key);
01014       }
01015 
01021     virtual PSafePtr<Base> GetAt(
01022       PINDEX idx,
01023       PSafetyMode mode = PSafeReadWrite
01024     ) {
01025         return PSafePtr<Base>(*this, mode, idx);
01026       }
01027 
01033     virtual PSafePtr<Base> FindWithLock(
01034       const Key & key,
01035       PSafetyMode mode = PSafeReadWrite
01036     ) {
01037         collectionMutex.Wait();
01038         PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
01039         collectionMutex.Signal();
01040         ptr.SetSafetyMode(mode);
01041         return ptr;
01042       }
01044 };
01045 
01046 
01051 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
01052 {
01053 };
01054 
01055 
01056 #endif // _SAFE_COLLECTION_H
01057 
01058 

Generated on Fri Mar 7 06:25:02 2008 for PTLib by  doxygen 1.5.1