BDE 4.14.0 Production release
|
Provide generic scoped guards for synchronization objects.
This component provides generic guards, bslmt::LockGuard
, bslmt::LockGuardUnlock
, and bslmt::LockGuardTryLock
, to automatically lock and unlock an external synchronization object. The synchronization object can be any type (e.g., bslmt::Mutex
or bslmt::RecursiveMutex
) that provides the following methods:
Both bslmt::LockGuard
and bslmt::LockGuardUnlock
implement the "construction is acquisition, destruction is release" idiom. During construction, bslmt::LockGuard
automatically calls lock
on the user-supplied object, and unlock
when it is destroyed (unless released). bslmt::LockGuardUnlock
does the opposite – it invokes the unlock
method when constructed and the lock
method when it is destroyed.
A third type of guard, bslmt::LockGuardTryLock
, attempts to acquire a lock, and if acquisition succeeds, releases it upon destruction. Since the acquisition is done at construction time, it is not possible to return a value to indicate success. Rather, the bslmt::LockGuardTryLock
contains a pointer to the synchronization object if tryLock
succeeds, and is null otherwise. The synchronization object can be any type (e.g., bslmt::Mutex
or bslmt::RecursiveMutex
) that provides the following methods:
Note that none of these guard types assumes ownership of the external synchronization object. Also note that objects of all of the guard types may be constructed with a null lock
whereby the constructed guard objects manage no lock. The destructor of each of the guard types has no effect if no lock is under management.
Like all BDE guard classes, each of the three bslmt::LockGuard*
classes provides a release
method that terminates the guard's management of any lock object that the guard holds. The release
method has no effect on the state of the lock object.
In particular, bslmt::ReadLockGuard::release
does not unlock the lock object under management. If a user wants to release the lock object and unlock the lock object (because the lock is no longer required before the guard goes out of scope), the following idiom can be used:
This section illustrates intended use of this component.
Use this component to ensure that in the event of an exception or exit from any point in a given scope, the synchronization object will be properly unlocked. The following function, errorProneFunc
, is overly complex, not exception safe, and contains a bug.
The function can be rewritten with a cleaner and safer implementation using a guard object. The safeFunc
function is simpler than errorProneFunc
, is exception safe, and avoids the multiple calls to unlock that can be a source of errors.
When blocking while acquiring the lock is not desirable, one may instead use a bslmt::LockGuardTryLock
in the typical following fashion:
Instantiations of bslmt::LockGuardUnlock
can be interleaved with instantiations of bslmt::LockGuard
to create both critical sections and regions where the lock is released.
Care must be taken so as not to interleave guard objects in such a way as to cause an illegal sequence of calls on a lock (two sequential lock calls or two sequential unlock calls on a non-recursive mutex).