
On Apr 28, 2005, at 11:58 PM, Matt Hurd wrote:
Howard Hinnant <hinnant@twcny.rr.com> wrote:
On Apr 28, 2005, at 9:31 PM, Michael Glassford wrote:
What happens when you request a shared lock from a non-shared mutex? It just gives you an exclusive lock?
Imho, a compile time error.
I disagree, which suggests perhaps it should be configurable to make us both happy.
A mutex has certain capabilities. Some mutexes may support shared access, some not. If a shared lock tries to "lock" a mutex, that means that it is trying to tell the mutex to "lock_sharable". If the mutex doesn't support that function, it should complain and loudly.
I can see performance issues, but I fail to see a correctness issue. Do you have an example?
I can imagine a failure on code that requires concurrent shared access from two or more threads, but I've never seen such code.
The best I can do for now is rather vague: Imagine a system where there is nothing but readers, but one specific reader needs to occasionally promote itself to exclusive access for a write. This specific reader is always either in write mode or read mode, never completely releasing the lock. All other readers are sometimes in read mode, and sometimes not holding a lock. The above system will work fine as long as all of the sharable locks really are sharable. Specifically, if the one promotable lock is really holding an exclusive lock in read mode (by mistake), then all other reader threads are permanently locked out of the resource. It could be that I misunderstood the original question. In an attempt to clarify... A homogenous (generic) interface is achieved at the lock level. That is, sharable_lock has a member function called lock() which calls lock_sharable() on the underlying mutex. A scoped (or exclusive) lock has a member function called lock() which calls lock() (or lock_exclusive()) on the underlying mutex. Code that is generic in locks, for example: // atomically lock two locks (without fear of deadlock) template <class TryLock1, class TryLock2> void lock(TryLock1& l1, TryLock2& l2); will work whether the two locks are exclusive, sharable, promotable, or some mix, as they all share the same generic interface (lock(), try_lock(), etc.). So in a sense, if mutexes retain a heterogeneous interface, implementing only what they can truly deliver, and locks wrap the mutex with a homogenous interface, then we really do have the choice you speak of.
PS: Here is my wishlist of mutex capabilities. But this list isn't meant to imply that all mutexes must support all of these capabilities. Locks should be able to pick and choose what they need out of a mutex, using only a subset of this functionality when appropriate. A lock templated on a mutex will only require those mutex capabilities actually instantiated by the lock client.
http://home.twcny.rr.com/hinnant/cpp_extensions/ threads_move.html#Summary%20of%20mutex%20operations
I'll have a look. It is certainly impressive looking. There is a lot of capability I've never needed there...
It is really nothing more than:
This gives you a substitutable taxonomy of null->exclusive->shareable->promotable.
except null is missing. I've never used null, except when I throw a master switch that says: Ok, everybody out of the pool except one guy! (single thread mode and everything becomes a null lock) :-) I'm also suggesting lock transfers therein, but using the syntax of move semantics suggested in the committee papers. Boost could use that syntax, but it would be much more of a pain to support in the current language, and a few minor things still wouldn't work, for example: template <class Lock, class Mutex> Lock<Mutex> source_lock(Mutex& m) { Lock<Mutex> lock(m); // do something with lock here // ... return lock; } That is, the above code is illegal today assuming locks aren't copyable. But legal tomorrow assuming that locks are movable. However, boost could make syntax like this work: upgradable_lock read_lock(mut); // mut read locked ... scoped_lock write_lock(move(read_lock)); // mut promoted to write lock It would involve auto_ptr_ref-like tricks in the locks. For example (of such tricks applied to smart pointers): http://www.kangaroologic.com/move_ptr/ -Howard