
Peter Dimov wrote:
Michael Glassford wrote:
Peter Dimov wrote:
Howard Hinnant wrote:
[ read/write mutexes and locks ]
Seems very good to me. Also demonstrates a better lock taxonomy
Better compared to what? The current read/write lock taxonomy? One of the many suggestions in this discussion?
Better compared to the current non-read-write lock taxonomy.
Lock
Lock( Mutex&, bool = true ); void lock(); void unlock(); bool locked() const; operator int bool_type::* () const;
TryLock: Lock
+bool try_lock();
TimedLock: TryLock
+bool timed_lock( xtime const & );
The point being that TryLock is a refinement of Lock, and TimedLock is a refinement of TryLock? If so, I agree that's better than TryLock and TimedLock both refining Lock. There are still the constructor issues to deal with in such a lock taxonomy, however.
I don't see any. There is one constructor, with the same behavior.
OK. I hadn't realized that you meant there to be literally only one constructor; I do now.
The main one: how do you define destructors that are consistent within a lock concept and also consistent between concepts.
~Lock { if( locked() ) unlock(); }
however it looks like you meant 'constructor'.
Sorry, I did mean constructor.
E.g., on the one hand it seems that a one-parameter constructor should do the same thing in all lock types--so it would have to block; on the other hand, it seems that TryLock constructors should not block unless instructed to do otherwise.
I meant what I said. There is a single constructor. Its behavior is consistent across all lock concepts (it it weren't, a TryLock would not be a Lock). A mutex exposes a single lock type, which is as refined as possible.
OK, that makes sense and is consistent (which I like). What about the following as an alternative? I retain the hierarchy (a TryLock is a Lock, a TimedLock is a TryLock) and resolve the conflict (of consistency within a concept and consistency across concepts) by the principle that a constructor always blocks unless you specifically tell it not to: Definitions ----------- M: appropriate mutex type namespace lock_state { typedef enum { unlocked=0, locked=1 } lock_state; } //namespace lock_state namespace read_write_lock_state { typedef enum { unlocked=0, read_locked=1, write_locked=2 } read_write_lock_state; } //namespace read_write_lock_state namespace blocking_mode { typedef enum { non_blocking=0, blocking=1 } blocking_mode; } //namespace blocking_mode ScopedLock / ScopedReadLock / ScopedWriteLock --------------------------------------------- lock(M) //always locking, blocking lock(M, lock_state) //blocking ScopedTryLock / ScopedTryReadLock / ScopedTryWriteLock ------------------------------------------------------ try_lock(M) //always locking, BLOCKING try_lock(M, lock_state) //BLOCKING try_lock(M, lock_state, blocking_mode) try_lock(M, blocking_mode) //always locking ScopedTimedLock / ScopedTimedReadLock / ScopedTimedWriteLock ------------------------------------------------------------ timed_lock(M) //always locking, blocking timed_lock(M, lock_state) //blocking timed_lock(M, lock_state, blocking_mode) timed_lock(M, blocking_mode) //always locking timed_lock(M, t) //always locking, blocking for time t