
Howard Hinnant wrote:
On Oct 30, 2007, at 3:43 PM, Yuval Ronen wrote:
2. Make sizeof(unique_lock) smaller - no need for bool owns. Even if we remove defer_lock, unique_lock will still need the internal bool to support try and timed locks. This functionality still retains a reference to the mutex even if the try/timed lock fails (so that further action with the mutex can be easily taken). This is something I don't understand. Why should the lock retain a reference to the mutex even if the try/timed lock fails?
Because if the try_lock fails, I might want to take some corrective action and then do a blocking lock() on the mutex. If the lock has retained the reference to the mutex, I don't have to store that reference elsewhere "just in case" the try_lock fails.
But now you do it (by "it" I mean "retained the reference, just in case") all the time, for everyone, even if unnecessary. I believe this is a rare use case (I never written or read such code), and it's also something that can be easily implemented externally (either as a unique_lock wrapper, or not). It seems pity that everyone should pay that cost.
In general it seems you paid a lot of attention to being able to pass a lock instead of a mutex wherever possible. I think it's absolutely not necessary. It's an undue complication. Actually I tried to pay attention to what the minimal requirements were on template parameters. It just turned out that some generic code would accept either locks or mutexes. But you made the effort of mentioning it several times in the document. That implies importance. My claim is that there is no importance to it, because there's no use for it, even if it happens that we named unique_lock::lock the same way we named mutex::lock. We could've have named them differently. And while I'm thinking of it, why is there a lock() method for unique_lock anyway? Isn't it unnecessary?
The original answer is because that's the way boost::scoped_lock specified its API. After further study and experience, I find myself in complete agreement with the boost API in this regard, at least for unique_lock. I think the member lock() functions on unique_lock are quite convenient. That being said, please see lock_guard in N2447 which both lacks the defer_lock functionality, and lacks member lock, try_lock and unlock functions. It also lacks the internal bool you would like to get rid of. I think we may already have what you're looking for, just under a different name.
What makes member lock() functions on unique_lock convenient? In other words, when are they convenient? I've skimmed N2447 very quickly, and it seems that lock_guard is a rename of scoped_lock, right? The major difference between lock_guard and a stripped unique_lock, is the moveability. There is no vector<lock_guard>, and if we are to support vector<unique_lock>, then we should support it well, which means reducing the used size by half.