# PSafeObject Class Reference

This class defines a thread-safe object in a collection. More...

`#include <safecoll.h>`

Inheritance diagram for PSafeObject:

List of all members.

## Public Member Functions

Construction
| PSafeObject (PSafeObject *indirectLock=NULL)
| Create a thread safe object.
Operations
PBoolean | SafeReference ()
| Increment the reference count for object.
PBoolean | SafeDereference ()
| Decrement the reference count for object.
PBoolean | LockReadOnly () const
| Lock the object for Read Only access.
void | UnlockReadOnly () const
| Release the read only lock on an object.
PBoolean | LockReadWrite ()
| Lock the object for Read/Write access.
void | UnlockReadWrite ()
| Release the read/write lock on an object.
void | SafeRemove ()
| Set the removed flag.
PBoolean | SafelyCanBeDeleted () const
| Determine if the object can be safely deleted.
virtual bool | GarbageCollection ()
| Do any garbage collection that may be required by the object so that it may be finally deleted.

## Detailed Description

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 of a PSafeCollection of PSafeObjects utilises the PSafePtr class in a classic "for loop" manner.

`for (PSafePtr<MyClass> iter(collection, PSafeReadWrite); iter != NULL; ++iter) iter->Process();`

There is one piece if important behaviour in the above. If while enumerating a specic object in the collection, that object is "safely deleted", you are guaranteed that the object is still usable and has not been phsyically deleted, however it will no longer be in the collection, so the enumeration will stop as it can no longer determine where in the collection it was.

What to do in this case is to take a "snapshot" at a point of time that can be safely and completely iterated over:

`PSafeList<MyClass> collCopy = collection; for (PSafePtr<MyClass> iter(callCopy, PSafeReadWrite); iter != NULL; ++iter) iter->Process();`

## Constructor & Destructor Documentation

PSafeObject::PSafeObject | ( | PSafeObject * | indirectLock = `NULL` | ) |

Create a thread safe object.

Parameters:

  indirectLock | Other safe object to be locked when this is locked

## Member Function Documentation

virtual bool PSafeObject::GarbageCollection | ( |  | ) | `[virtual]`

Do any garbage collection that may be required by the object so that it may be finally deleted.

This is especially useful if there a references back to this object which this object is in charge of disposing of. This reference "glare" is to be resolved by this function being called every time the owner collection is cleaning up, causing a cascade of clean ups that might need to be required.

Default implementation simply returns true.

Returns:
  true if object may be deleted.

PBoolean 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.

PBoolean 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.

PBoolean 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.

Returns:
  true if reference count has reached zero and is not being safely deleted elsewhere ie SafeRemove() not called

PBoolean 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.

PBoolean 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.

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.

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.

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.

The documentation for this class was generated from the following file:

- safecoll.h