PWLib
1.10.10
|
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