
On Aug 4, 2004, at 4:45 PM, Bronek Kozicki wrote:
Is there any reason for distinction between shared lock and upgradable shared lock? I mean - obviously updgradable shared lock can be upgraded to exclusive one, but do we need separate type for this? What's rationale behind this distinciton? I can easily imagine design (and implementation) where every shared lock is also upgradable one, if it's mutex type support upgrade operation. Under such design one can upgrade shared lock only if it's the only (currently locking) lock on synchromization object (supporting such transition). Implementation of such mutex could be very similar to semaphore (or just using semaphore, if present on platform).
The advantage of the separate upgradable_lock type is that when an upgradable_lock transfers ownership to a scoped_lock, then the thread can assume that what was read while holding upgradable ownership is still valid (does not need to be re-read, re-computed) while holding the scoped_lock. This is true even if the thread had to block while transferring mutex ownership from the upgradable_lock to the scoped_lock. If sharable_lock can transfer mutex ownership to scoped_lock, then the thread can no longer make this assumption. If the thread blocks for this ownership transfer, it is possible that another thread will interrupt, upgrade a sharable_lock, and write. The original thread, upon obtaining the scoped_lock, is forced to re-read or re-compute its data upon obtaining the scoped_lock ownership because of this possibility. Thus it might as well just have relinquished shared ownership and blocked for exclusive ownership. Having said that, it is true that we could add: bool try_unlock_sharable_and_lock(); to the mutex functionality. This would mean adding the following to scoped_lock: scoped_lock(rvalue_ref<sharable_lock<mutex_type> > r, detail::try_lock_type); scoped_lock& operator<<=(rvalue_ref< sharable_lock<mutex_type> > r); Meaning, you could try to upgrade a sharable_lock to a scoped_lock, but there would be no way to force the upgrade. It adds an unsymmetric aspect to the interface: every other try-function has a corresponding blocking function. Aside from the asymmetry, I also wonder about the practicality of such an operation. A shared_lock context is usually set up because one anticipates common simultaneous non-destructive locking. If simultaneous non-destructive locking is rare, there is no advantage over exclusive locking. So if simultaneous non-destructive locking is common, that means a successful call to try_unlock_sharable_and_lock() will be rare (and if it isn't, then a simple exclusive mutex would have probably been a better design). It occurs to me that offering such an interface might be encouraging an interface that blocks a thread indefinitely (just keeps trying). Whereas if the code had just relinquished shared ownership and blocked for exclusive, then the mutex design is likely to already be set up to not starve writers. -Howard