
Howard Hinnant wrote:
On Jul 12, 2004, at 11:28 AM, Peter Dimov wrote:
Howard Hinnant wrote:
On Jul 11, 2004, at 8:46 AM, Peter Dimov wrote:
[...]
Mutex * mutex() const; // returns: the associated mutex;
Why return a pointer instead of a reference? What about this instead?
Mutex& mutex(); const Mutex& mutex() const;
Because of the use case shown below:
void f( scoped_lock & lock ) { // check for lock validity assert( lock.locked() && lock.mutex() == &my_mutex );
// proceed with operation }
A pointer makes it clear that it is the identity of the associated mutex that is being queried. A (const-"correct") reference return implies that the purpose of the accessor is to return, well, a reference to the mutex object, presumably so that the client can do something with it.
That would put to rest any questions about mutex() transferring mutex ownership, e.g.:
delete lock.mutex();
I considered
bool is_associated_with( Mutex const & m ) const;
but that's a bit too much of a handholding for my taste, and doesn't allow us to use mutex() in the Effects clauses. The kind of a person that would delete lock.mutex() would never get a multithreaded program correct anyway.
If we expose either a Mutex* or a Mutex&, and we standardize a public Mutex interface (with lock(), unlock(), etc.), then we are saying that one can call functions on the pointer or reference returned by mutex(). And now that I write that sentence my skin is beginning to crawl. ;-)
I have occasionally seen a need for using a mutex outside of a scoped_lock, when the lock/unlock pattern is not as neat as what scoped_lock provides. Alexander's read/write lock algorithm is a good example: http://groups.google.com/groups?selm=3B166244.F923B993%40web.de . And so I do not object to standardizing a public mutex interface so that they can be used outside of a scoped_lock. But allowing a mutex to be manipulated within a scoped_lock seems dangerous.
Brainstorming:
template <class Mutex> bool operator==(const scoped_lock<Mutex>&, const Mutex&);
template <class Mutex> bool operator==(const Mutex&, const scoped_lock<Mutex>&);
instead of Mutex* scoped_lock::mutex() const;
?
Might look like:
void f( scoped_lock & lock ) { // check for lock validity assert( lock.locked() && lock == my_mutex );
// proceed with operation }
Haven't even prototyped it, so I'm not even sure it will work. Just a thought.
If you don't want people messing with the mutex through the scoped_lock, use a void* disguised as a typedef: typedef void const* mutex_id_type; struct mutex { mutex_id_type id() const { return this; } ... }; template< class Mutex > { Mutex & m_; mutex_id_type mutex_id() const { return m_.id(); } }; Usage might look like: void f( scoped_lock & lock ) { // check for lock validity assert( lock.locked() && lock.mutex_id() == my_mutex.id() ); // proceed with operation } -- Eric Niebler Boost Consulting www.boost-consulting.com