|
Boost : |
From: Eric Niebler (eric_at_[hidden])
Date: 2004-07-12 15:22:22
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk