
Howard Hinnant <hinnant <at> twcny.rr.com> writes:
Exploring the case: throw exception if unable to atomically promote read to write:
If an exception is not thrown, then you are guaranteed what you previously read is still true, and all is well. If an exception is thrown, then you have to re-read to determine current state.
Hmm...
Given that when you have write privilege you also implicitly have read privilege, this seems a little extreme. Would it not be both more efficient and easier to follow if you just reaffirm your state under the write lock rather than assume your state, and write a catch block to reassert it if it happens to be false?
If you have to re-check the state under a promoted lock, then you don't need lock promotion - you just need to begin the operation a second time, with a write lock. This will be exactly the same thing, with the various pieces of code correctly scoped.
void do_sale(rw_mutex& m) { read_lock rl(m);
long balance = get_balance(); long cost = get_total_cost();
if (balance > cost) { rl.unlock(m); write_lock wl(m); set_balance(balance - cost);
You can't do this operation without first checking that the cost and balance have not changed since the read lock was unlocked.
wl.transfer_to_read_lock(rl); balance = get_balance(); } // ... }
[snip]
My assertion is that you don't know a-priori if the read-to-write promotion achieves anything or not. If you allow it to fail, by exception, or by error code, or by any other means, then you have to write code to re-read the current state.
If a promotion fails, you not only need to read state again, you also need to release your existing read lock to allow the thread that beat you to lock promotion to proceed. With scoped locks, I think it is easier to handle this with an exception, and a repeat of the failed portion of code, than to release and re-acquire the locks manually.
If you don't allow it to fail, then you must make it block until it succeeds.
This isn't possible, since if you fail promotion, you must also release your extant read lock to allow the other promoted lock to proceed. Actually, I guess it is possible, but the code still reads incorrectly with the naive assumption that a scoped lock is maintained throughout its scope.
The latter seems simpler in logic, and smaller in code size. The logic is quite simple:
read_lock to write_lock promotion is not atomic.
If it isn't atomic, then it isn't promotion - it is misleading to have it in the interface, since the programmer must be aware that promotion may have invalidated any prior knowledge that had been protected by the earlier read lock.
Once that is understood, the programmer can just deal with it. Trying to encapsulate this bit of reality only serves to obfuscate the necessary logic.
-Howard
Yes. But OTOH, it can be atomic-with-the-possibility-of-failure, which has the benefit of not requiring state to be re-checked. It also has clear semantics in the case of failure which the programmer can deal with. Matt