Phx::LockedAccessor< T > Class Template Reference
A LockedAccessor offers access to a piece of data while a lock protecting the data is held.
More...
#include <PhxAccessors.h>
Inheritance diagram for Phx::LockedAccessor< T >:
List of all members.
|
Public Member Functions |
| | LockedAccessor (const T &data, Lock *lock) |
| | Constructs a LockedAccessor that offers access to its data while a given lock is held.
|
| | LockedAccessor (const T &data, LockHolder *lockHolder) |
| | Constructs a locked accessor that offers access to its data while holding the lock already acquired via a LockHolder.
|
| T & | data () |
| | Returns the protected data to the client.
|
Detailed Description
template<class T>
class Phx::LockedAccessor< T >
A LockedAccessor offers access to a piece of data while a lock protecting the data is held.
A LockedAccessor is an object that simply contains a LockHolder and a copy of some data protected by that lock. For as long as this object is in existance, the data may be safely accessed under the protection provided by the lock. When this object is destructed, the lock holder is destroyed and the lock released.
The client can access the data via the data() method.
The template parameter T is the data type that is held by this object. The lock is interpreted as protecting the contents of the T object that is held. It does NOT protect the reference to the T itself. That is, the lock belongs to the T, and not to the object that contains T.
Consider the a situation where the pointer to a piece of data (dataPtr) needs to be returned to the client. The pointer may change as a result of concurrent access and hence is protected by a lock called 'lock'. The following is incorrect:
Ptr<LockedAccessor<Data*> > lockedAcc(new LockedAccessor<Data*>(dataPtr, &lock));
return lockedAcc;
Because the lock is acquired in the constructor of LockedAccessor, we are referencing dataPtr (to pass it to the constructor as a parameter) before we acquire the lock. This is wrong since we said that dataPtr might change and hence accesses to it must be protected by the lock. The following is the correct solution:
LockHolder lockHolder(&lock);
Ptr<LockedAccessor<Data*> > lockedAccPtr(new LockedAccessor<Data*>(dataPtr, &lockHolder));
return lockedAccPtr;
Note that in this case the lock is acquired before the constructor to protect our access to dataPtr. The LockHolder object is passed in place of the lock itself, allowing transfer of the lock to the LockedAccessor. After this is complete, the source lock holder no longer owns the lock.
- Remarks:
- Copy construction and assignment are disallowed. You should refer to a LockedAccessor as a smart pointer (Ptr).
The template parameter T must be a copy-constructable and assignable type.
- Todo:
- This derives from LockedPtrInterface. This is a good candidate for optimization, since deriving from PtrInterface would save us several lock operations every time this is used. The BaseListener framework uses this object and incurs 5 lock and 5 unlock operations every time the listener attribute is accessed. With the standard PtrInterface it incurs just 1 of each.
Constructor & Destructor Documentation
|
|
Constructs a LockedAccessor that offers access to its data while a given lock is held.
- Parameters:
-
| data | The value to set for the data field when this object is initialized. If the lock must be taken before the data is stored (e.g., if the lock must protect access to the data object itself, not just its contents) then you should acquire the lock first yourself (with a LockHolder object) and then hand-off that lock to this object using LockedAccessor(T, LockHolder*). See the documentation at the head of this class for a short example of this situation. |
| lock | A raw pointer to the Lock that protects the data. This lock will be held for as long as this object is in use and will be released upon its destruction. |
- Warning:
- Creating multiple LockedAccessor objects will cause a deadlock, since the constructor of each attempts to take the lock.
|
|
|
Constructs a locked accessor that offers access to its data while holding the lock already acquired via a LockHolder.
- Parameters:
-
| data | The value to set for the data field when this object is initialized. |
| lockHolder | The LockHolder object that already controls the lock protecting this data. That LockHolder will pass the lock to this LockedAccessor which will hold it until releasing it on destruction. On return, 'lockHolder' no longer is in control of the lock and will do nothing on its destruction. |
|
Member Function Documentation
|
|
Returns the protected data to the client.
The client can use the returned object to perform all of its operations. In general, it's most efficient to simply access the contained object directly as in: Ptr<LockedAccessor<T> > myPtr(T( .. ), lock, false);
myPtr->data().foo();
Since data() is likely to be inlined, this is fast and simple.
- Warning:
- The client could store a copy of the reference and then access it, rather than "calling" data() each time. The disadvantage is two-fold. First, copying the object is a minor but unnecessary inefficiency. Second, passing copies of the "unprotected" data around requires extra care. Once the LockedAccessor that issued the object is destroyed, the lock protecting the data will be released. As a result, any accesses made via outstanding copies of the object may not be safe depending on its relation to the original data. Thus, if you make copies of the data returned by this method (e.g., when passing it to another function), you should be sure that all references to the original (protected) data are destroyed, or at least that they are treated appropriately once the lock is released.
- Returns:
- A reference to the data contained by this locked accessor.
|
The documentation for this class was generated from the following file:
Generated on Wed Dec 21 22:05:39 2005 for Phoenix OSFS by
1.4.2