#include <safecoll.h>
Inheritance diagram for PSafeObject:
Public Member Functions | |
Operations | |
BOOL | SafeReference () |
BOOL | SafeDereference () |
BOOL | LockReadOnly () const |
void | UnlockReadOnly () const |
BOOL | LockReadWrite () |
void | UnlockReadWrite () |
void | SafeRemove () |
BOOL | SafelyCanBeDeleted () const |
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
PSafeObject::PSafeObject | ( | PSafeObject * | indirectLock = NULL |
) |
Create a thread safe object.
indirectLock | Other safe object to be locked when this is locked |
PSafeObject::PSafeObject | ( | PSafeObject * | indirectLock = NULL |
) |
Create a thread safe object.
indirectLock | Other safe object to be locked when this is locked |
BOOL PSafeObject::SafeReference | ( | ) |
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 PSafeObject::SafeDereference | ( | ) |
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.
BOOL PSafeObject::LockReadOnly | ( | ) | const |
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.
void PSafeObject::UnlockReadOnly | ( | ) | 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.
BOOL PSafeObject::LockReadWrite | ( | ) |
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.
void PSafeObject::UnlockReadWrite | ( | ) |
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 PSafeObject::SafeRemove | ( | ) |
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.
BOOL PSafeObject::SafelyCanBeDeleted | ( | ) | const |
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.