|
Boost : |
From: Eric Niebler (eric_at_[hidden])
Date: 2004-07-08 02:12:07
Michael Glassford wrote:
> Eric Niebler wrote:
>>
>> How about:
>>
>> if( ScopedLock l = try_lock( m ) )
>> {
>> }
>>
>> where try_lock is function that returns a simple wrapper class:
>>
>> template< Mutex > struct try_locker
>> {
>> Mutex & m;
>> ...
>> };
>>
>> template< Mutex > try_locker< Mutex > try_lock( Mutex & m )
>> {
>> return try_locker< Mutex >( m );
>> };
>>
>> and ScopedLock is some lockable type which has a constructor that
>> accepts a try_locker. (It would also need a bool-ish conversion to
>> allow the lock to be declared in the "if" statement, but that's not
>> relevant to this discussion.)
>
>
> Interesting idea. I suppose you could even do this:
>
> if (ScopedLock l(m, locker()))
> {
> }
>
> where locker() is a function object that defines
>
> operator()(LockType& l)
>
> which the lock calls in the constructor, passing *this. You could have
> locker(), try_locker(), timed_locker(t), etc.
>
>
Not quite. In order to declare and initialize a variable in an "if"
statement, you need to use the "if( type var = fun() )" form, where the
"=" is necessary.
I realize that the code I posted before is incompatible with the
requirement that ScopedLock be non-copyable. Below is an interesting
variation which works around the problem. It defines a single type
"lock" which is non-copyable, yet it can be returned by value from a
function. (This may or may not be desirable for a lock class, but it's
interesting.)
struct lock;
lock try_lock();
struct lock_ref
{
lock_ref(lock & ref)
: ref_(ref)
{
}
lock & ref_;
};
struct lock
{
lock(lock_ref ref){}
operator lock_ref()
{
// ... move the lock ...
return lock_ref(*this);
}
operator bool() const
{
// TODO return true iff we're holding the lock
return true;
}
private:
friend lock try_lock();
lock(/*params*/){} // a try-lock c'tor
// make this type non-copyable, non-assignable
lock(lock &);
lock & operator=(lock &);
};
inline lock try_lock(/*params*/)
{
// call a special try-lock c'tor on lock
return lock(/*params*/);
}
int main()
{
if( lock l = try_lock(/*params*/) )
{}
}
The idea is to have just one lock class (leaving aside read/write locks)
and a collection of factory functions like try_lock(), timed_lock(),
defered_lock() etc. Those functions create a lock object by calling the
appropriate (private) constructor and returning the new lock object.
(Some fancy auto_ptr-like move shenanigans are needed to make the lock
return-able but not copy-able.)
I'm not really advocating this design. I'm not close enough to this
problem to have a strong preference. Just offering it as an alternative.
-- 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