|
Boost : |
From: Christopher Currie (codemonkey_at_[hidden])
Date: 2004-07-16 12:41:59
Michael Glassford wrote:
> I believe there was (nearly?) consensus that we want to make locks
> movable at some point. My conclusion was that at that point this syntax
> becomes possible, too. I think Peter said or implied much the same
> thing, maybe before I did.
I'm just going to be the voice of dissent here, again, and argue that
the scoped_locks, at least, should not be moveable, otherwise they're
not very scoped. The scoped lock serves a specific purpose in ensuring
that the mutex doesn't remain locked outside of block scope, just like
scoped_ptr ensures that a heap object has a specific lifetime.
If there's enough hew and cry for a movable lock, then we should create
a new class for it. That said, most of the arguments I could find on the
list archive for it are to support syntax changes in initializing a
scoped lock. I also saw an argument for storing locks in containers,
which I can't quite fathom the need for, but I welcome the use cases.
As a compromise, we could create lock_transfer<> objects that wouldn't
lock a mutex, but would allow initialization syntax in places where the
language makes it difficult (this is just a quick sketch, there may be
errors):
template <typename Mutex> class lock_transfer;
template <typename Mutex> class try_lock_transfer;
template <typename Mutex>
lock_transfer<Mutex> lock( Mutex & m );
template <typename Mutex>
try_lock_transfer<Mutex> try_lock( Mutex & m );
template <typename Mutex>
class lock_transfer
{
private:
friend class scoped_lock<Mutex>;
friend class scoped_try_lock<Mutex>;
friend lock_transfer<Mutex> lock<>( Mutex & m );
Mutex & m_;
explicit lock_tranfer( Mutex & m ) : m_( m ) { }
};
template <typename Mutex>
lock_transfer<Mutex> lock( Mutex & m )
{
return lock_transfer<Mutex>( m );
}
template <typename Mutex>
class try_lock_transfer
{
private:
friend class scoped_try_lock<Mutex>;
friend try_lock_transfer<Mutex> try_lock<>( Mutex & m );
Mutex & m_;
explicit try_lock_tranfer( Mutex & m ) : m_( m ) { }
};
template <typename Mutex>
try_lock_transfer<Mutex> try_lock( Mutex & m )
{
return try_lock_transfer<Mutex>( m );
}
template <typename Mutex>
class scoped_lock
{
Mutex & m_;
public:
explicit scoped_lock( Mutex & m )
: m_( m ) { lock(); }
// blocking lock transfer
explicit scoped_lock( lock_transfer<Mutex> const & t )
: m_( t.m_ ) { lock(); }
scoped_lock & operator=( lock_tranfer<Mutex> const & t )
: m_( t.m_ ) { lock(); return *this; }
operator /* convertible to bool */() const
{ return locked(); }
};
template <typename Mutex>
class scoped_try_lock
{
Mutex & m_;
public:
explicit scoped_try_lock( Mutex & m )
: m_( m ) { try_lock(); }
// blocking lock transfer
explicit scoped_lock( lock_transfer<Mutex> const & t )
: m_( t.m_ ) { lock(); }
scoped_lock & operator=( lock_tranfer<Mutex> const & t )
: m_( t.m_ ) { lock(); return *this; }
// try lock transfer
explicit scoped_lock( try_lock_transfer<Mutex> const & t )
: m_( t.m_ ) { try_lock(); }
scoped_lock & operator=( try_lock_tranfer<Mutex> const & t )
: m_( t.m_ ) { try_lock(); return *this; }
operator /* convertible to bool */() const
{ return locked(); }
};
void foo()
{
mutex m;
try_mutex try_m;
if ( mutex::scoped_lock l = lock( m ) ) // always true
{
// do stuff
}
if ( mutex::scoped_lock l = try_lock( m ) ) // compile error!
{
// never reached
}
if ( try_mutex::scoped_try_lock l = lock( m ) ) // always true
{
// do stuff
}
if ( try_mutex::scoped_try_lock l = try_lock( m ) ) // may be false
{
// do stuff
}
}
Comments and critique welcome,
Christopher
-- Christopher Currie <codemonkey_at_[hidden]>
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk