
I've been mentioning that I have some ideas about improvements for Boost.Threads. I intend to bring up these ideas one at a time for discussion. I'm particularly interested in finding out: 1) Whether people think that the idea would be an improvement. 2) If so, suggestions for improving the idea even more. The first idea has to do with the long discussion that occured some time back about the lock class--in particular, its constructors. There were several ideas about whether lock constructors should make the full range of lock, try_lock, and timed_lock functionality available and, if so, how; I don't recall any consensus being reached. I experimented for a while with a series of template classes that would allow a user to choose whatever interface they wanted, but another idea has occured to me since then that I don't remember being mentioned anywhere (if I'm wrong, my apologies to whoever mentioned it): to eliminate the locking contructors altogether. In this scheme, a lock object would no longer be responsible for locking a mutex, only for unlocking it. Instead, a mutex object would lock itself and transfer ownership of the lock to a lock object by way of a lock_transfer object. A sample of what the classes would look like and their usage is given at the end of this message. Some advantages I see to this approach: #1: it simplifies the lock class and allows it to be used to lock any costructor, no matter what its type (it can own a lock to an exclusive mutex, an exclusive lock to a shared_mutex, or a shared lock to a shared_mutex). #2: instead of the following, which in my mind leaves an ambiguity of whether the mutex should be unlocked, shared-locked, or exclusive-locked at the end: shared_lock l1(shared_mutex, SHARED_LOCK); ... { exclusive_lock l2 = l1.promote(); ... } It is possible to write this, which removes the ambiguity: lock l = shared_mutex.shared_lock(); ... l = shared_mutex.promote(l.transfer()); ... Comments? Mike //------------------------------ //Exclusive mutex usage examples //------------------------------ mutex_type m; lock_type l; //Create lock object that doesn't lock anything lock_type l = m.lock(); //Create lock object and lock mutex m lock_type l = m.try_lock(); //Create lock object and conditionally lock mutex m lock_type l = m.timed_lock(xxx); //Create lock object and conditionally lock mutex m l = m.lock(); //Lock mutex m (first unlocking whatever mutex l was previously locking, if any) l = m.try_lock(); //Conditionally lock mutex m (first unlocking whatever mutex l was previously locking, if any) l = m.timed_lock(xxx); //Conditionally lock mutex m (first unlocking whatever mutex l was previously locking, if any) l = other_lock.transfer(); //Transfer the lock from one lock object to another l.unlock(); //Unlock whatever mutex is locked (throw exception if nothing is locked) l.is_locked(); //Is l locking a mutex? //NOT ALLOWED: l.lock(), l.try_lock(), etc.; //------------------------------ //Shared mutex usage examples //------------------------------ lock_type l; //Create unlocked lock object lock_type l = m.lock(); //Create lock object and lock mutex m lock_type l = m.try_lock(); //Create lock object and conditionally lock mutex m lock_type l = m.timed_lock(xxx); //Create lock object and conditionally lock mutex m lock_type l = m.shared_lock(); //Create lock object and shared-lock mutex m lock_type l = m.shared_try_lock(); //Create lock object and conditionally shared-lock mutex m lock_type l = m.shared_timed_lock(xxx); //Create lock object and conditionally shared-lock mutex m l = m.lock(); //Lock mutex m (first unlocking whatever mutex l was previously locking, if any) l = m.try_lock(); //Conditionally lock mutex m (first unlocking whatever mutex l was previously locking, if any) l = m.timed_lock(xxx); //Conditionally lock mutex m (first unlocking whatever mutex l was previously locking, if any) l = m.shared_lock(); //Shared-lock mutex m (first unlocking whatever mutex l was previously locking, if any) l = m.try_shared_lock(); //Conditionally shared-lock mutex m (first unlocking whatever mutex l was previously locking, if any) l = m.timed_shared_lock(xxx); //Conditionally shared-lock mutex m (first unlocking whatever mutex l was previously locking, if any) lock_type l = other_lock.transfer(); l = other_lock.transfer(); l = m.promote(l.transfer()); l = m.try_promote(l.transfer()); l = m.timed_promote(l.transfer(), xxx); l = m.demote(l.transfer()); l = m.try_demote(l.transfer()); l = m.timed_demote(l.transfer(), xxx); l.unlock(); //Unlock whatever mutex is locked (throw exception if nothing is locked) l.is_locked(); //Is l locking a mutex? //NOT ALLOWED: l.lock(), l.try_lock(), etc.; //------------------------------ //Class definitions //------------------------------ class lock_transfer { public: //Used to return ownership of a lock from a mutex or //to transfer ownership of a lock from one lock object to another lock_transfer(...) {...} ~lock_transfer() { //unlock the mutex if ownership of the lock //hasn't been taken by a lock object } ... }; class lock { public: lock(void) { //create lock object that doesn't lock any mutex ... } lock(lock_transfer& transfer) { //copy necessary information out of transfer ... } ~lock() {if (is_locked()) unlock();} lock_transfer transfer(void) { ... } void unlock(void) { //unlock the mutex ... } bool is_locked(void) { ... } }; class mutex { public: mutex(void); ~mutex(); lock_transfer lock(void); //lock the mutex and return a lock_transfer lock_transfer try_lock(void); lock_transfer timed_lock(...); ... }; class shared_mutex { public: mutex(void); ~mutex(); lock_transfer lock(void); lock_transfer try_lock(void); lock_transfer timed_lock(time t); lock_transfer shared_lock(void); lock_transfer try_shared_lock(void); lock_transfer timed_shared_lock(time t); lock_transfer demote(lock_transfer& exclusive_lock); lock_transfer try_demote(lock_transfer& exclusive_lock); lock_transfer timed_demote(lock_transfer& exclusive_lock, time t); lock_transfer promote(lock_transfer& shared_lock); lock_transfer try_promote(lock_transfer& shared_lock); lock_transfer timed_promote(lock_transfer& shared_lock, time t); ... };