
On Jul 22, 2004, at 2:37 PM, Eric Niebler wrote:
The scoped_lock assignment operators make me a bit nervous. For instance, you don't specify what this should do:
Mutex mut; scoped_lock< Mutex > l1( mut ); // lock once scoped_lock< Mutex > l2( mut ); // lock twice (recursive) l1 = move(l2); // ???
If I had to guess, I suppose this would have the effect of simply unlocking l2. Or should it throw? I would prefer the former if I had to choose, but the specification should be clear on this point.
Excellent point. I did not consider the possibility of a recursive mutex when I wrote the spec for this, nor when I prototyped it. You've found a bug in both the spec and my prototype. The (proposed) move assignment philosophy is: l1 = move(l2); behaves as if: atomic { if (l1.locked()) l1.unlock(); if (l2.locked()) { l2.unlock(); l1.lock(); } } So in your example l2 would be unlocked, l1 would remain locked, and the underlying mutex lock count would be decremented by 1. Proposed spec: Effects: Throws a lock_error() if mutex() != sl.p_->mutex(). If locked() before the call, then unlock() is called on the mutex. Postconditions: locked() == the value of sl.p_->locked() before the assignment. sl.p_->locked() == false after the assignment. Notes: This scoped_lock relinquishes any mutex ownership it has. Then if the sl scoped_lock owns the mutex, ownerhisp is transferred to this scoped_lock with no blocking. If the sl scoped_lock does not own the mutex, then neither will this scoped_lock after the assignment. Only rvalue scoped_lock's will match this signature. lvalue scoped_lock's can not transfer ownership unless "cast" to an rvalue. An lvalue scoped_lock can be "cast" to an rvalue with the expression: move(lock); Thanks for the catch. -Howard