$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Aleksey Gurtovoy (alexy_at_[hidden])
Date: 2000-01-06 16:03:11
From: Andy Glew <glew_at_[hidden]>
> A challenge:
>
> It sure would be nice if we could write, in C++, a template
>     mutexed<T>
> that ensured full mutually exclusion for any arbitrary type T.
> That did not have to know about the methods of T.
>
> I was about to start my usual moaning about  C++ not really
> allowing transparent proxying - to fully proxy something in C++
> you need to enumerate all of its methods - but I think that we might
> be able to come close.
>
> Here's a stab at it using some helper macros. (Yeah, well, I hope
> that someone can eliminate the macros.)
>
I will try to do so below ;)
> template<typename T>
> class mutexed {
> private:
>     lock_t lockvar;    // any lock you want - I'll assume just a lock bit
>                            // handled by primitive processor instructions
>     T value;
> public:
>     void acquire_lock() { lock.acquire_lock(); }
>     void release_lock() { lock.release_lock(); }
> public:
>     // constructors don't require locks on constructee
>     mutexed() :
>         lock(0),  // default unlocked
>         value()   // must have a default constructor;
>                        // must be constructible without locking
>         {}
>    mutexed(const mutexed& from) :
>         lock(0),
>         value()
>         {
>           from.lock.acquire_lock();
>           this->value = from.value;
>           from.lock.release_lock();
>           // or, use constructor locking, if you want locks released on
exceptions
>         }
> public:
>     // assignment requires locks on both sides
>     T& operator=(mutexed<T>& rhs) {
>        assert(this->lock);
>        { rhs.lock.acquire_lock();
>           this->value = rhs.value;
>           rhs.lock.release_lock();
>           // or, use constructor locking, if you want locks released on
exceptions
>         }
>     }
> public:
>     // destructor - checks lock?
>     ~mutexed() {
>             assert(lock == 0);    // your choice
>     }
> public:
>     // only allow access via ->
>     // which checks lock
>     // (if I could have -> enforce lock, I'd use that)
>     T* operator->() {
>         assert(lock);
>         return this;
>     }
> };
>
>
[snip]
> I was hoping that you could do just
>
>         mutexed<T> mobj;
>         mobj->method();        // implicitly mutexed
>
> although I don't see how to do this
>
You can achive this, if you implement auto_lock<> template like this:
template<class T>
class auto_lock {
  public:
    auto_lock( mutexed<T>& ref )
      : mutexed_ref_( ref )
      { mutexed_ref_.lock.acquire_lock(); }
    ~auto_lock() { mutexed_ref_.lock.release_lock(); }
    T* operator ->() const { return &mutexed_ref_.value; }
  private:
    mutexed<T>& mutexed_ref_;
};
and change the implementation of mutexed<T>::operator->() to something like:
template<typename T>
class mutexed {
....
public:
    auto_lock<T> operator->() {
        assert(lock);
        return auto_lock<T>( *this );
    }
};
and now this must (??) work:
mutexed<T> mobj;
mobj->method();        // *is* implicitly mutexed
-Alexy