Subject: Re: [boost] [thread] On shared_mutex
From: Jeffrey Lee Hellrung, Jr. (jhellrung_at_[hidden])
Date: 2010-11-28 19:07:16
On 11/28/2010 3:57 PM, Howard Hinnant wrote:
> On Nov 28, 2010, at 6:38 PM, Jeffrey Lee Hellrung, Jr. wrote:
>> On 11/28/2010 12:52 PM, Howard Hinnant wrote:
>>> Three years ago I wrote N2406 "Mutex, Lock, Condition Variable Rationale" (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html) for the C++ committee in an attempt to explain the combined proposed std::mutex/std::unique_lock package and how it fit together with the tr2-targeted shared_mutex/shared_lock package. This paper also proposed an upgrade_mutex and upgrade_lock.
>>> Since that time, the std-proposed stuff has been accepted with some name changes, and a reworking of the timed-locking interface. Additionally Anthony Williams has implemented much of the shared-locking functionality in boost (and done a very nice job with it).
>>> That being said, I disagree with some fairly major design changes between N2406 and what is now in the boost library. Four of the major changes are:
>>> There is a tutorial-style description of this library here:
>> In the section "Upgrade Locking", where you list the member functions of ting::upgrade_mutex that are called in the (first) average function, I'm not sure the list is complete, and I want to make sure I understand what's going on.
>> I agree that mut_.lock() and a.mut_.lock_upgrade() are called upon construction of this_lock and share_that_lock, respectively.
>> I'd only expect mut_.unlock() and a.mut_.unlock_upgrade() to be called if an exception is thrown in the for-loop. Is that correct? If so, it might be helpful to make this more explicit; if not, please explain why.
>> I agree that mut_.unlock_and_lock_shared() and a.mut_.unlock_upgrade_and_lock() are called upon construction of share_this_lock and that_lock, respectively.
>> Finally, a.mut_.unlock() and mut_.unlock_shared() will be called, and in that order, upon destruction of that_lock and share_this_lock, respectively.
>> I believe you're missing a final unlock() function call.
>> The exposition could also be improved slightly if you indicate on *which* mutex (mut_ or a.mut_) the locking and unlocking member functions are invoked. But primarily, I just want to make sure I got this right ;)
> I think you've got it right (nice job).
> I'm a little hesitant to get more detailed here. The intent was to do a bit of hand waving to motivate the reader into using the locks and not the mutex member functions. Diving deeper I think one could argue that nothing is ever going to throw in this function, though we could make another example that could throw to demonstrate the point. I haven't listed any function twice as this is meant to be a list of functions that are called, and not necessarily which function that is called in which order (which may vary depending on whether an exception is throw and where).
Ah, okay, I think I read a little more into it than you intended, then.
> I'm hoping to keep this section as short as possible and for the take-away message to be:
> Don't use mutex member functions!!!
> (unless you're doing something low-level like implementing a lock)
I'm now confused with the implementation of try_lock_until...let's start
with the first line:
std::unique_lock<L0> u0(l0, t)
So...L0 is itself a lock (specifically an ExclusiveLock, I would guess,
although the second implementation of average is using a
"Lock"...typo?), so I don't think this makes sense. Should be something
like l0.try_lock_until(t) ???
Also, there a few references to "diagrams to the right" throughout the
text that aren't showing up in my firefox browser. Any suggestions?
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk