📄 safecoll.h
字号:
/* * safecoll.h * * Thread safe collection classes. * * Portable Windows Library * * Copyright (c) 2002 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): ______________________________________. * * $Log: safecoll.h,v $ * Revision 1.14 2004/11/08 02:34:18 csoutheren * Refactored code to (hopefully) compile on Linux * * Revision 1.13 2004/11/07 12:55:38 rjongbloed * Fixed safe ptr casting so keeps associated collection for use in for loops. * * Revision 1.12 2004/10/28 12:19:44 rjongbloed * Added oeprator! to assure test for NULL that some people use is correct for PSafePtr * * Revision 1.11 2004/10/14 12:31:45 rjongbloed * Added synchronous mode for safe collection RemoveAll() to wait until all objects * have actually been deleted before returning. * * Revision 1.10 2004/10/04 12:54:33 rjongbloed * Added functions for locking an unlocking to "auto-unlock" classes. * * Revision 1.9 2004/08/12 12:37:40 rjongbloed * Fixed bug recently introduced so removes deleted object from deletion list. * Also changed removal list to be correct type. * * Revision 1.8 2004/08/05 12:15:56 rjongbloed * Added classes for auto unlocking read only and read write mutex on * PSafeObject - similar to PWaitAndSIgnal. * Utilised mutable keyword for mutex and improved the constness of functions. * Added DisallowDeleteObjects to safe collections so can have a PSafeObject in * multiple collections. * Added a tempalte function to do casting of PSafePtr to a PSafePtr of a derived * class. * Assured that a PSafeObject present on a collection always increments its * reference count so while in collection it is not deleted. * * Revision 1.7 2002/12/10 07:36:57 robertj * Fixed possible deadlock in PSafeCollection find functions. * * Revision 1.6 2002/10/29 00:06:14 robertj * Changed template classes so things like PSafeList actually creates the * base collection class as well. * Allowed for the PSafeList::Append() to return a locked pointer to the * object just appended. * * Revision 1.5 2002/10/04 08:22:40 robertj * Changed read/write mutex so can be called by same thread without deadlock * removing the need to a lock count in safe pointer. * Added asserts if try and dereference a NULL safe pointer. * Added more documentation on behaviour. * * Revision 1.4 2002/09/16 01:08:59 robertj * Added #define so can select if #pragma interface/implementation is used on * platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan. * * Revision 1.3 2002/08/29 06:51:11 robertj * Added optimisiation, separate mutex for toBeRemoved list. * * Revision 1.2 2002/05/06 00:44:45 robertj * Made the lock/unlock read only const so can be used in const functions. * * Revision 1.1 2002/05/01 04:16:43 robertj * Added thread safe collection classes. * */ #ifndef _SAFE_COLLECTION_H#define _SAFE_COLLECTION_H#ifdef P_USE_PRAGMA#pragma interface#endif/** This class defines a thread-safe object in a collection. This is part of a set of classes to solve the general problem of a collection (eg a PList or PDictionary) of objects that needs to be a made thread safe. Any thread can add, read, write or remove an object with both the object and the database of objects itself kept thread safe. The act of adding a new object is simple and only requires locking the collection itself during the add. Locating an object is more complicated. The obvious lock on the collection is made for the initial search. But we wish to have the full collection lock for as short a period as possible (for performance reasons) so we lock the individual object and release the lock on the collection. A simple mutex on the object however is very dangerous as it can be (and should be able to be!) locked from other threads independently of the collection. If one of these threads subsequently needs to get at the collection (eg it wants to remove the object) then we will have a deadlock. Also, to avoid a race condition with the object begin deleted, the objects lock must be made while the collection lock is set. The performance gains are then lost as if something has the object locked for a long time, then another object wanting that object will actually lock the collection for a long time as well. So, an object has 4 states: unused, referenced, reading & writing. With the additional rider of "being removed". This flag prevents new locks from being acquired and waits for all locks to be relinquished before removing the object from the system. This prevents numerous race conditions and accesses to deleted objects. The "unused" state indicates the object exists in the collection but no threads anywhere is using it. It may be moved to any state by any thread while in this state. An object cannot be deleted (ie memory deallocated) until it is unused. The "referenced" state indicates that a thread has a reference (eg pointer) to the object and it should not be deleted. It may be locked for reading or writing at any time thereafter. The "reading" state is a form of lock that indicates that a thread is reading from the object but not writing. Multiple threads can obtain a read lock. Note the read lock has an implicit "reference" state in it. The "writing" state is a form of lock where the data in the object may be changed. It can only be obtained exclusively and if there are no read locks present. Again there is an implicit reference state in this lock. Note that threads going to the "referenced" state may do so regardless of the read or write locks present. Access to safe objects (especially when in a safe collection) is recommended to by the PSafePtr<> class which will manage reference counting and the automatic unlocking of objects ones the pointer goes out of scope. It may also be used to lock each object of a collection in turn. The enumeration */class PSafeObject : public PObject{ PCLASSINFO(PSafeObject, PObject); public: /**@name Construction */ //@{ /**Create a thread safe object. */ PSafeObject(); //@} /**@name Operations */ //@{ /**Increment the reference count for object. This will guarantee that the object is not deleted (ie memory deallocated) as the caller thread is using the object, but not necessarily at this time locking it. If the function returns FALSE, then the object has been flagged for deletion and the calling thread should immediately cease using the object. A typical use of this would be when an entity (eg a thread) has a pointer to the object but is not currenty accessing the objects data. The LockXXX functions may be called independetly of the reference system and the pointer beiong used for the LockXXX call is guaranteed to be usable. It is recommended that the PSafePtr<> class is used to manage this rather than the application calling this function directly. */ BOOL SafeReference(); /**Decrement the reference count for object. This indicates that the thread no longer has anything to do with the object and it may be deleted (ie memory deallocated). It is recommended that the PSafePtr<> class is used to manage this rather than the application calling this function directly. */ void SafeDereference(); /**Lock the object for Read Only access. This will lock the object in read only mode. Multiple threads may lock the object read only, but only one thread can lock for read/write. Also, no read only threads can be present for the read/write lock to occur and no read/write lock can be present for any read only locks to occur. If the function returns FALSE, then the object has been flagged for deletion and the calling thread should immediately cease use of the object, possibly executing the SafeDereference() function to remove any references it may have acquired. It is expected that the caller had already called the SafeReference() function (directly or implicitly) before calling this function. It is recommended that the PSafePtr<> class is used to automatically manage the reference counting and locking of objects. */ BOOL LockReadOnly() const; /**Release the read only lock on an object. Unlock the read only mutex that a thread had obtained. Multiple threads may lock the object read only, but only one thread can lock for read/write. Also, no read only threads can be present for the read/write lock to occur and no read/write lock can be present for any read only locks to occur. It is recommended that the PSafePtr<> class is used to automatically manage the reference counting and unlocking of objects. */ void UnlockReadOnly() const; /**Lock the object for Read/Write access. This will lock the object in read/write mode. Multiple threads may lock the object read only, but only one thread can lock for read/write. Also no read only threads can be present for the read/write lock to occur and no read/write lock can be present for any read only locks to occur. If the function returns FALSE, then the object has been flagged for deletion and the calling thread should immediately cease use of the object, possibly executing the SafeDereference() function to remove any references it may have acquired. It is expected that the caller had already called the SafeReference() function (directly or implicitly) before calling this function. It is recommended that the PSafePtr<> class is used to automatically manage the reference counting and locking of objects. */ BOOL LockReadWrite(); /**Release the read/write lock on an object. Unlock the read/write mutex that a thread had obtained. Multiple threads may lock the object read only, but only one thread can lock for read/write. Also, no read only threads can be present for the read/write lock to occur and no read/write lock can be present for any read only locks to occur. It is recommended that the PSafePtr<> class is used to automatically manage the reference counting and unlocking of objects. */ void UnlockReadWrite(); /**Set the removed flag. This flags the object as beeing removed but does not physically delete the memory being used by it. The SafelyCanBeDeleted() can then be used to determine when all references to the object have been released so it may be safely deleted. This is typically used by the PSafeCollection class and is not expected to be used directly by an application. */ void SafeRemove(); /**Determine if the object can be safely deleted. This determines if the object has been flagged for deletion and all references to it have been released. This is typically used by the PSafeCollection class and is not expected to be used directly by an application. */ BOOL SafelyCanBeDeleted() const; //@} protected: mutable PMutex safetyMutex; unsigned safeReferenceCount; BOOL safelyBeingRemoved; mutable PReadWriteMutex safeInUseFlag;};/**Lock a PSafeObject for read only and automatically unlock it when go out of scope. */class PSafeLockReadOnly{ public: PSafeLockReadOnly(const PSafeObject & object); ~PSafeLockReadOnly(); BOOL Lock(); void Unlock(); BOOL IsLocked() const { return locked; } bool operator!() const { return !locked; } protected: PSafeObject & safeObject; BOOL locked;};/**Lock a PSafeObject for read/write and automatically unlock it when go out of scope. */class PSafeLockReadWrite{ public: PSafeLockReadWrite(const PSafeObject & object); ~PSafeLockReadWrite(); BOOL Lock(); void Unlock(); BOOL IsLocked() const { return locked; } bool operator!() const { return !locked; } protected: PSafeObject & safeObject; BOOL locked;};/** This class defines a thread-safe collection of objects. This class is a wrapper around a standard PCollection class which allows only safe, mutexed, access to the collection. This is part of a set of classes to solve the general problem of a collection (eg a PList or PDictionary) of objects that needs to be a made thread safe. Any thread can add, read, write or remove an object with both the object and the database of objects itself kept thread safe. See the PSafeObject class for more details. Especially in regard to enumeration of collections. */class PSafeCollection : public PObject{ PCLASSINFO(PSafeCollection, PObject); public: /**@name Construction */ //@{ /**Create a thread safe collection of objects. Note the collection is automatically deleted on destruction. */ PSafeCollection( PCollection * collection /// Actual collection of objects );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -