Boost logo

Boost :

From: Matthew Vogt (mvogt_at_[hidden])
Date: 2004-07-05 22:08:31


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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk