A simple locking-proxy class template (execute-around-pointer idiom): at construction locks the given mutex and provides -> access to the given target object; at destruction unlocks it.
More...
|
| | Locked_proxy (Target *target, Mutex *mutex) |
| | Locks *mutex – blocking as-needed until that is possible – and makes *this proxy *target. More...
|
| |
| | Locked_proxy (Locked_proxy &&src_moved) |
| | Move constructor: *this acts as src_moved would-have (in particular its eventual destruction unlocks the mutex), while src_moved becomes a no-op object permanently. More...
|
| |
|
| Locked_proxy (const Locked_proxy &)=delete |
| | Prohibit copying: for each explicit ctor invocation, there shall be exactly 1 unlocking dtor invocation.
|
| |
|
Locked_proxy & | operator= (const Locked_proxy &)=delete |
| | Prohibit copying (see deleted copy ctor).
|
| |
|
Locked_proxy & | operator= (Locked_proxy &&)=delete |
| | Prohibit modifying existing *this; except that moving-from is enabled via the move ctor.
|
| |
| Target * | operator-> () const |
| | Returns pointer to the target object, the guarding mutex being locked by *this (do not use if moved-from). More...
|
| |
| Target & | operator* () const |
| | Returns reference to the target object, the guarding mutex being locked by *this (do not use if moved-from). More...
|
| |
template<typename Target_t, typename Mutex_t>
class flow::util::Locked_proxy< Target_t, Mutex_t >
A simple locking-proxy class template (execute-around-pointer idiom): at construction locks the given mutex and provides -> access to the given target object; at destruction unlocks it.
In typical use one obtains *this as an unnamed temporary in the middle of an expression, so that the mutex is locked for exactly that expression's duration. E.g., given Widget w and a mutex m serializing all access to w – suppose some w_locked() returns Locked_proxy{&w, &m}:
const auto n = w_locked()->compute_n();
This is the execute-around-pointer idiom. The typical motivation: some class C internally owns both a mutex-protected object and the mutex, its background/concurrent machinery locking the latter as needed; and wants to let its user safely invoke methods of that object. Then C can supply a w_locked()-style accessor as sketched above – instead of writing a delegating, internally-locking method for every operation of interest. The set of available operations then maintains itself, as does the correctness of each such call's locking.
To grant read-only (const methods only) access, simply use a const-qualified Target type: e.g., Locked_proxy<const Widget, ...>.
Keep it to one expression
*this existing = the mutex being locked. The intended use is as an unnamed temporary (see above example): then the lock is held for a few microseconds, and it is impossible to leak. If you do save a *this to extend the locked section, keep the scope tight: whatever machinery normally locks that mutex is blocked in the meantime.
- See also
boost::synchronized_value implements the same idiom but owns both the payload and the mutex ("wrap your data in me"). *this, by contrast, is non-owning: it is for objects whose guarding mutex exists independently – e.g., one that guards more state than just the target object.
- Template Parameters
-
| Target_t | Type of the object to which *this proxies access; possibly const-qualified (see above). |
| Mutex_t | A Lockable-concept mutex type, e.g. util::Mutex_non_recursive. |
Definition at line 248 of file util.hpp.