Boost logo

Boost :

From: klaus triendl (klaus_at_[hidden])
Date: 2008-04-02 16:46:02


Phil Endecott schrieb:
> Hi Klaus,

Hi Phil,

sorry for being quiet for some time, I was on holidays...

> I finally got around to looking at this. Yes, it does what I expect it to.
>
> One detail I noticed was that you make the mutex mutable, so that you
> can lock a const object. This is something that I have worried about,
> because I fear that there are "gotchas". Do any experts have opinions
> about this?

Hmm, what "gotchas" could you think of?
The idea is that e.g. one thread shares a lockable and is allowed to
write to it and other threads share a lockable but only get read access
- this is expressed with the const-qualifier on the lockable.
I would think of different ways, e.g. to refine const/non-const with
derivation:

<code>
template<typename T, typename T_mutex>
struct lockable:
   boost::mpl::eval_if<
     std::tr1::is_const<T>,
     lockable_base<T_mutex>,
     lockable<const T>
>::type
{
   // ...
};
</code>

> I said before that I found my own locking pointer (or locking
> reference) was more verbose than explicitly locking the mutex and
> accessing the data, and so have not used it much. I've now remembered

Do you think that using the lock_acquirer is too verbose, too? I admit
that it is verbose... The intent is to force a named lvalue
lock_acquirer object.
I like the idea of Frank's suggestion for an operator *().

> another practical problem with it. Here's the code without Lockable<>:
>
> void start_updater(mutex& m, int& val)
> {
> // spawn a thread that periodically locks m and changes val
> }
>
> mutex m;
> array<int,100> values;
>
> for (int i=0; i<100; ++i) {
> start_updater(m,values[i]);
> }
>
>
> The point is that all of the values share a mutex. Our Lockable<>
> classes could be used here if you wanted one mutex per value, but that
> could be wasteful and perhaps wrong. How can we adapt Lockable<> to
> work in this sort of situation? I'm wondering about something like this:
>
> Lockable< array<int,100 > values;
>
> for (int i=0; i<100; ++i) {
> start_updater(LockableRef<int>(values,values[i]);
> }
>
> i.e. LockableRef contains a reference to the mutex and one element of
> its "parent" Lockable<>, and presents the same interface as a data-full Lockable<>.
>
> But because Lockable and LockableRef aren't actually the same type, I
> can't write
>
> void start_updater(Lockable<int> i);
>
> and use it with both.
>
> Is this something that you have thought about?

Well, I didn't think about this one. But what do you think of the following?

<code>
template<typename T_type, typename T_mutex>
struct lockable //: ...
{
     // ...

     // return a lockable_ref, see below
     lockable_ref<std::tr1::remove_extent<T_type>, T_mutex>
     operator [](std::size_t idx)
     {
         return lockable_ref<std::tr1::remove_extent<T_type>,
T_mutex>(access_volatile()[idx], mutex());
     }
};

// a lockable_ref like I imagine it
template<typename T_type, typename T_mutex>
struct lockable_ref: lockable_tag
{
     // copy construct from rvalue and lvalue ref
     lockable_ref(lockable_ref&& rvalue):
         //parent_type(rvalue.mutex()),
         m_mutex_ref(rvalue.mutex()),
         m_obj_ref(rvalue.access_volatile())
     {}

     // implicitly construct from lockable
     typedef lockable<T_type, T_mutex> lockable_type;
     lockable_ref(lockable_type& rvalue):
         //parent_type(rvalue.mutex()),
         m_mutex_ref(rvalue.mutex()),
         m_obj_ref(rvalue.access_volatile())
     {}

     // construct from a variable and a mutex
     lockable_ref(T_type& rvalue, T_mutex& rmutex):
         //parent_type(rvalue.mutex()),
         m_mutex_ref(rmutex),
         m_obj_ref(rvalue)
     {}

     T_mutex& m_mutex_ref;
     T_type& m_obj_ref;
};
</code>

now you can write start_updater like this:

<code>
void start_updater(lockable_ref<int, mutex> i)
{
}

lockable<array<int, 100>, mutex> values;
lockable<int, mutex> one_value;

for (int i=0; i<100; ++i) {
    start_updater(values[i]);
}

start_updater(one_value);
</code>

Klaus


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