|
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