Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2007-08-22 13:47:37


On Aug 22, 2007, at 1:07 PM, Yuval Ronen wrote:

> Howard Hinnant wrote:
>> On Aug 22, 2007, at 11:22 AM, Yuval Ronen wrote:
>>
>>> Howard Hinnant wrote:
>>>> On Aug 22, 2007, at 8:05 AM, Yuval Ronen wrote:
>>>>
>>>>> Yuval Ronen wrote:
>>>>>> Howard Hinnant wrote:
>>>>>>
>>>>>>> Because of this, it is
>>>>>>> not possible (in the above use case) for there to be a set_mutex
>>>>>>> on
>>>>>>> the condition to change the facade, since both facades are
>>>>>>> simultaneously in use.
>>>>>> Yes, I've realized that too late. My set_mutex() function is
>>>>>> useless
>>>>>> because it has to be atomic with the wait().
>>>>> I've just thought that it might be not so useless after all.
>>>>> 'set_mutex'
>>>>> is supposed to be called after the mutex was locked, and before
>>>>> calling
>>>>> condition::wait. Because the mutex is locked, we are protected
>>>>> against
>>>>> simultaneous use. There can be a problem when multiple readers
>>>>> lock
>>>>> for
>>>>> read, and simultaneously call set_mutex, but if we assume they all
>>>>> set
>>>>> the same mutex it shouldn't be a problem.
>>>> How would wake from wait be handled? I.e. what mutex (facade)
>>>> would
>>>> it use to lock with? The last one set may not correspond to the
>>>> proper one on wake.
>>> It would lock the same mutex it unlocked upon entering wait().
>>
>> Could you prototype or sketch this out? Sorry, I'm not following.
>
> Perhaps some code will help me clarify my ideas (taking your
> advice :) ):
>
> template <class Mutex>
> class condition
> {
> typedef Mutes mutex_type;
> mutex_type *m_mutex;
>
> public:
> condition() : m_mutex(NULL) { }
> explicit condition(mutex_type &a_mutex) : m_mutex(&a_mutex) { }
>
> void set_mutex(mutex_type &a_mutex) { m_mutex = &a_mutex; }
>
> void wait()
> {
> assert(m_mutex); // overhead only in debug builds
> do_wait(*m_mutex);
> }
> };
>
> Of course that's a very partial implementation, but I hope it's enough
> to convey my intent.

It is the do_wait function that I didn't know how to implement. But
maybe something like:

do_wait(mutex_type& m)
{
     internal_mutex.lock();
      mutex_type* local_m = &m;
      m.unlock();
      sleep on internal_mutex;
      internal_mutex.unlock();
      local_m->lock();
}

The local_m is used in case someone calls set_mutex with another
facade while we're sleeping. I think that will work, but of course
haven't tested it.

Now looking at the client side:

shared_mutex mut;
condition<shared_mutex> cv;

void foo()
{
     scoped_lock<shared_mutex> _(mut.exclusive());
     while (cant_write())
     {
         cv.set_mutex(mut.exclusive())
         cv.wait();
     }
     // now safe to write to protected data
}

Does that look about right for what you are suggesting?

I guess the facades are member data in the shared_mutex? If not, who
manages their storage?

I at first put the call to set_mutex outside the while-statement, but
then realized that doesn't work. Someone else could set_mutex while
you're sleeping, then you get a spurious wakeup, then you sleep with
the wrong facade on the next iteration. So you have to use the
set_mutex directly before the call to wait().

-Howard


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