Boost logo

Boost :

From: Michael Glassford (glassfordm_at_[hidden])
Date: 2004-06-30 09:49:01


Anthony Williams wrote:
> Michael Glassford <glassfordm_at_[hidden]> writes:
>
>
>>Peter Dimov wrote:
>>
>>>Michael Glassford wrote:
>>>
>>>
>>>>Also, you could end up with some interesting situations like this:
>>>>
>>>> void f(read_write_mutex m)
>>>> {
>>>> read_write_mutex::read_lock r(m);
>>>> if (...)
>>>> {
>>>> read_write_mutex::write_lock w(r); //lock promotion
>>>> //...
>>>> }
>>>> //Point A
>>>> }
>>>>
>>>>The most obvious implementation of promotion would be for the write lock
>>>>to unlock the read lock if promotion succeeded, but leave it locked if
>>>>promotion failed. But in the above code, this would mean that if
>>>>promotion succeeds, neither lock will be locked at "Point A"; however
>>>>if promotion fails, r will still be read-locked at point A.
>>>
>>>Not necessarily, ~write_lock can (should) demote the lock back to read (or
>>>whatever the initial condition of r was).
>>
>>True. But then, in the reverse case:
>>
>> void f(read_write_mutex m)
>> {
>> read_write_mutex::write_lock w(m);
>> if (...)
>> {
>> read_write_mutex::read_lock r(w); //lock demotion
>> //...
>> }
>> //Point A
>> }
>>
>>It may not be possible for r's destructor to re-obtain the write lock
>
>
> I don't think this usage should be allowed.

How would it be prevented?

> Once you have a write lock (the
> "higher class" of lock), then you keep your write lock until you release
> it. If you want a read lock for the whole time, but only a write lock for a
> portion of that time, then you write code like the first example. Your
> "reverse case" actually fulfils that requirement, since there is a portion of
> the code that only needs a read lock. Therefore it should look like:
>
>
> void f(read_write_mutex m)
> {
> read_write_mutex::read_lock r(m); // we need at least a read lock
> // for everything
> {
> read_write_mutex::write_lock w(r);
> // do stuff that needs the write lock here
> }
> if (...)
> {
> // we only need the read lock here
> //...
> }
> {
> read_write_mutex::write_lock w(r);
> // do more stuff that needs the write lock here
> }
> }

Again, this might be a better way to write it, but how do you prevent
someone from writing it the first way?

I think one of the most common use cases for lock demotion would be:
obtain a write lock and make modifications to a resource; demote to a
read lock to release other readers and use the resource, making sure
that it is still in the state it was when we had the write lock (i.e.,
that no other thread obtained a write lock and changed it between the
time we released our write lock and the time we obtained our read lock).

With a read/write lock, this is expressed in a straightforward way:

     void f(read_write_mutex m)
     {
         read_write_mutex::write_lock l(m);

         //Modify the resource

         l.demote(); //Release other readers

         //Use the resource
     }

With the separate read-lock and write-lock, how do you express this in a
way that is straightforward, doesn't do unnecessary work when the locks
are released, etc.?

Mike


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