Boost logo

Boost :

From: klaus triendl (klaus_at_[hidden])
Date: 2008-03-18 05:20:14


vicente.botet schrieb:
>> Inspired by Andrei Alexandrescu's article "volatile - Multithreaded
>> Programmer's Best Friend" on ddj I implemented a concept similar to a
>> locking pointer called "lock_acquirer" that collects acquisition of a
>> mutex and a volatile cast of the locked type. It is even more threadsafe
>> to use than a locking pointer.
>
> I'm interested in your implementation, but much more in seen how this
> lock_acquirer differs from the locking_ptr and in seen how it can works with
> the shared mutex.
> Could you be more explicit about how it is more threadsafe?
>
> There are other locking pointer like inspired also by Andrei Alexandrescu's
> work that will be interesting as
> on_derreference_locking_ptr(on_derreference_lock_acquirer) and
> externally_locked.

Hi Vicente,

I expressed myself too vague - the lock_acquirer itself isn't more
threadsafe than a locking_ptr but the way the programmer has to use it
leads to more threadsafe programming behaviour, I believe. Everything
depends on the usage scenario, of course.

A locking_ptr takes the lockable (locker, or whatever you call it) and
provides access via operator ->() and operator *(); thus you can write:
<code>
lockable<T, mutex> l;
T* p = locking_ptr<lockable<T, mutex> >(l).operator ->();
T& o = *locking_ptr<lockable<T, mutex> >(l);
</code>

... constructing the locking_ptr and accessing an object in a single line.

lock_acquirer doesn't aim to be a smart pointer (though I like also the
idea of having an automatic locking while accessing an object's method).
It is constructed from a lockable but access to the object is only
granted via a protected friend template function forcing to pass a named
lock_acquirer object:
<code>
lockable<T, mutex> l;
lock_acquirer<lockable<T, mutex> > a(l);
T& o = access_acquiree(a);
</code>

An additional bonus of lock_acquirer is that the programmer can specify
a locking policy (read/write) as a template parameter and the
lock_acquirer selects an appropriate r/w lock for the given mutex type.
If the locking policy is read access then lock_acquirer grants
const-access only to the synchronized object even if T in lockable<T> is
non-const:
<code>
lockable<int, mutex> l;
// readlock_acquirer derives from
// lock_acquirer<readlock, lockable<int, mutex> >
readlock_acquirer<lockable<int, mutex> > a(l);
const int& o = access_acquiree(a);
</code>

>> Also, the locked type in a lockable can, if wanted, by a restricted
>> interface only be accessed by a lock_acquirer thus forcing the
>> programmer to a very threadsafe programming style.
>
> Could you show us how?

The lockable type has public access methods, a safe_lockable however
makes lock_acquirer a friend:

template<typename T, typename T_mutex>
struct safe_lockable: public lockable_base<T_mutex>
{
     template<...> friend class lock_acquirer;

protected:
     volatile_T& access_volatile();
     T& access_nonvolatile();
};

Klaus


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk