|
Boost : |
From: Raoul Gough (RaoulGough_at_[hidden])
Date: 2002-09-30 05:21:39
"Darryl Green" <green_at_[hidden]> wrote on gmane.comp.lib.boost.user
news:696BA06B3A0FD211BAAD0060B0C4DD8301FD3F14_at_WNTX...
> > From: Raoul Gough [mailto:yg-boost-users_at_[hidden]]
> > Sent: Friday, 27 September 2002 9:44 PM
[snip]
> > The proxy copy constructor would unlock() the original lock
> > and construct the copy using the original's mutex (which is
> > the part that can't currently work, because there is no
> > public access to a lock's mutex). Assuming that the compiler
> > implements the NRVO, the unlock/lock sequence wouldn't
> > actually happen, and the client code just gets its proxy
> > object constructed for it. If the compiler doesn't implement
> > the NRVO, the code still works, but is less efficient.
>
> This issue has come up before on the development list (search for
> Boost.Threads Locking Delima). I'm not sure that it was resolved
> satisfactorily - move semantics for scoped_locks seemed to be the
answer,
> but I think there were problems actually implementing that. The
intent was
> that if move couldn't be implemented, then the mutex lock methods
would have
> to be exposed.
Hi, Darryl. Thanks for the pointer - move semantics is what I was
looking for. How are things going at tabq?
If anyone is interested, I've come up with an improved proxy
implementation that provides move semantics using the existing
boost::scoped_lock. It stores its own reference to the original mutex,
which is only slightly less efficient than if scoped_lock had move
semantics itself. This allows code like the following:
void foo (mt::holder<std::deque<int> > &queue)
{
queue()->push_back (5); // thread-safe
}
Regards,
Raoul Gough.
// Proxy template
#include <boost/thread/mutex.hpp>
namespace mt
{
template<typename T>
class proxy
{
boost::mutex &mMutex;
boost::mutex::scoped_lock mLock;
T *mPtr;
boost::mutex &release ()
{
mLock.unlock();
return mMutex;
}
public:
proxy (proxy &other)
: mMutex (other.release())
, mLock (mMutex)
, mPtr (other.mPtr)
{
}
template<typename TOwner> proxy (TOwner &owner)
: mMutex (owner.mutex())
, mLock (mMutex)
, mPtr (&owner.data())
{
}
T *get() const { return mPtr; }
T &operator* () const { return *mPtr; }
T *operator-> () const { return mPtr; }
};
}
// Holder with thread-safe proxy access:
#include "proxy.hh"
#include <boost/thread/mutex.hpp>
namespace mt
{
template<typename T>
class holder
{
template<typename X> friend class proxy;
public:
typedef proxy<T> proxy_type;
typedef proxy<T> returnable_proxy_type;
holder () : mMutex (), mT () { }
explicit holder (T const &t) : mMutex (), mT (t) { }
returnable_proxy_type operator() ();
// Convenience function. It is more efficient for the caller
// to construct a proxy<T> directly from the holder object.
private:
// Proxy support methods. These allow a proxy<T> to construct
// itself from us (accessible via friendship).
boost::mutex &mutex () { return mMutex; }
T &data () { return mT; }
private:
boost::mutex mMutex;
T mT;
};
template<typename T>
typename holder<T>::returnable_proxy_type
holder<T>::operator() ()
{
returnable_proxy_type temp (*this);
return temp;
}
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk