
Christopher Currie wrote:
Michael Glassford wrote:
To address these problems, I would like to redefine the lock concept constructors as follows (changes indicated with "^"):
Definitions ----------- L: lock type l: lock variable (type L) m: mutex variable (appropriate Mutex type) s: initial lock state (enum type {NO_LOCK=0, LOCK=1}) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ b: block? (enum type blocking_state {NON_BLOCKING=0, BLOCKING=1}) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Lock Concept ------------ L l(m,s) //Blocking lock if s L l(m) //Blocking lock
TryLock Concept --------------- L l(m,s,b) //Lock if s; blocking if b ^ ^^^^^^^^^^^^^ L l(m,b) //Lock; blocking if b ^ ^^^^^^^^^^^^^
TimedLock Concept ----------------- L l(m,s,b) //Lock if s; blocking if b ^ ^^^^^^^^^^^^^ L l(m,t) //Blocking lock, failing if not obtained by time t
I like this proposal, if for no other reason than the move to enums makes the arguments clearer. A couple of points:
Yes, I like LOCK and NO_LOCK better than true and false for the same reason.
TryLock: What would be the semantics of l(m, NO_LOCK, b)? In other words, if you're not going to lock on construction, why specify a blocking policy?
The only reason is so that if you write l(m, LOCK, ...) you could also specify the blocking parameter. An expansion of Vladimir Batov's of using structs rather than enums could help here: struct nolock_t {}; nolock_t nolock; struct lock_t {}; lock_t lock; class TryLock { TryLock(TryMutex m, no_lock_t s) {...} TryLock(TryMutex m, lock_t s, blocking_t b) {...} }
L l(m, b) and L l(m, s) seem to cover the two scenarios: either I don't want to lock, or I do and I need to specify the blocking policy.
TimedLock: I'm not sure I follow the reasons why TimedMutex refines TryMutex. (This is a comment on the original design, not your specific changed, but bear with me.) I think a timeout of zero seconds achieves the same goal, even if TimedLock/TimedMutex don't implement the same operations. So I don't think that TimedLock needs a constructor that takes a blocking argument, and ultimately I think TimedLock/TimedMutex should refine Mutex/Lock, and not TryMutex/TryLock.
Also, the current implementation of TimedLock doesn't support a single argument constructor, even though it is supposedly a refinement of TryLock, which does. I'd like to see TimedLock implemented in such a way that I could use it as if it were a simple Lock, which I currently cannot. In summary, this is what I'd like to see:
Lock Concept --------------- L l(m) //Blocking lock L l(m,s) //Blocking lock if s
TryLock Concept --------------- As Lock, *plus:* L l(m,b) //Lock; blocking if b
TimedLock Concept ----------------- As Lock (not TryLock), *plus:* L l(m,t) //Blocking lock, failing if not obtained by time t //If t == 0, acts as TryLock.
As I said in another post, I'll think about this some more. Thanks for taking the time to comment. Mike