Boost logo

Boost :

From: Jeff Mirwaisi (jeff_mirwaisi_at_[hidden])
Date: 2003-10-23 07:28:52


Below is a simple guard type that i have found useful,
there are still a couple of issues, but perhaps it’s
interesting enough to pursue as a possible addition to
the boost thread library

template <typename T, typename LOCK_TYPE =
empty_mutex, template <typename> class LOCK_ADAPTER =
empty_mutex_adapter > struct locked_ref : private
LOCK_ADAPTER<LOCK_TYPE>
{
  struct trule : private LOCK_ADAPTER<LOCK_TYPE>
  {
    trule(const locked_ref& l) :
LOCK_ADAPTER<LOCK_TYPE>(l),t_(l.t_),release_(true)
{const_cast<locked_ref&>(l).release_=false;}
    trule(const trule& rhs) :
LOCK_ADAPTER<LOCK_TYPE>(rhs),t_(rhs.t_),release_(true)
{const_cast<trule&>(rhs).release_=false;}
    ~trule() {if (release_) this->release();}
    T* operator->() const {return &t_;}
    T& operator*() const {return t_;}
  private:
    friend struct locked_ref;
    trule(trule&); //discourage use as lvalue, causes
warning in vc 7.1
    trule& operator=(const trule&);
    T& t_;
    bool release_;
  };

  locked_ref(T& t,LOCK_TYPE& l) :
LOCK_ADAPTER<LOCK_TYPE>(l),t_(t),release_(true)
{this->acquire();}
  locked_ref(const trule& tr) :
LOCK_ADAPTER<LOCK_TYPE>(tr),t_(tr.t_),release_(true)
{const_cast<trule&>(tr).release_=false;}
  ~locked_ref() {if(release_) this->release();}
  T* operator->() const {return &t_;}
  T& operator*() const {return t_;}
 private:
  friend struct trule;
  //even with trules this should probable be public,
  //would allow us to return a temporary locked_ref as
a trule, and to use locked_ref t = locked_ref()
  locked_ref(const locked_ref& rhs); //:
LOCK_ADAPTER<LOCK_TYPE>(rhs),t_(rhs.t_),release_(true)
{this->acquire();}
  locked_ref & operator=(const locked_ref&);
  T& t_;
  bool release_;
};

Attached is a simple test application and a
demonstration of a couple of the shortcomings

__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com

#include <iostream>

//fake mutex for testing
struct empty_mutex
{
  unsigned int i_;
  empty_mutex() : i_(0) {}
  void acquire() {std::cout << ++i_ << std::endl;}
  void release() {std::cout << --i_ << std::endl;}
};

//pass through adapter
template <typename LOCK_TYPE> struct empty_mutex_adapter
{
  empty_mutex_adapter(LOCK_TYPE& m) : m_(m) {}
  void acquire() {m_.acquire();}
  void release() {m_.release();}
private:
  LOCK_TYPE& m_;
};

template <typename T, typename LOCK_TYPE = empty_mutex, template <typename> class LOCK_ADAPTER = empty_mutex_adapter > struct locked_ref : private LOCK_ADAPTER<LOCK_TYPE>
{
  struct trule : private LOCK_ADAPTER<LOCK_TYPE>
  {
    trule(const locked_ref& l) : LOCK_ADAPTER<LOCK_TYPE>(l),t_(l.t_),release_(true) {const_cast<locked_ref&>(l).release_=false;}
    trule(const trule& rhs) : LOCK_ADAPTER<LOCK_TYPE>(rhs),t_(rhs.t_),release_(true) {const_cast<trule&>(rhs).release_=false;}
    ~trule() {if (release_) this->release();}
    T* operator->() const {return &t_;}
    T& operator*() const {return t_;}
  private:
    friend struct locked_ref;
    trule(trule&); //discourage use as lvalue, causes warning in vc 7.1
    trule& operator=(const trule&);
    T& t_;
    bool release_;
  };

  locked_ref(T& t,LOCK_TYPE& l) : LOCK_ADAPTER<LOCK_TYPE>(l),t_(t),release_(true) {this->acquire();}
  locked_ref(const trule& tr) : LOCK_ADAPTER<LOCK_TYPE>(tr),t_(tr.t_),release_(true) {const_cast<trule&>(tr).release_=false;}
  ~locked_ref() {if(release_) this->release();}
  T* operator->() const {return &t_;}
  T& operator*() const {return t_;}
 private:
  friend struct trule;
  //even with trules this should probable be public,
  //would allow us to return a temporary locked_ref as a trule, and to use locked_ref t = locked_ref()
  locked_ref(const locked_ref& rhs); //: LOCK_ADAPTER<LOCK_TYPE>(rhs),t_(rhs.t_),release_(true) {this->acquire();}
  locked_ref & operator=(const locked_ref&);
  T& t_;
  bool release_;
};

//simple test client
class test
{
  empty_mutex mtx_;
  int value_;
public:
  //hidden copy constructor, so we cant return temporary directly
  locked_ref<int>::trule get_value() {locked_ref<int> t(value_,mtx_); return t;}
  locked_ref<test>::trule get_test() {locked_ref<test> t(*this,mtx_); return t;}
};

//template parameter deduction fails
template <typename T,typename L> void f0(typename locked_ref<T,L>::trule const& p) {}
template <typename T,typename L> void f1(locked_ref<T,L> const& p) {}

//template function cant deduce T and L above when used with trule
void f2(locked_ref<test>::trule const&) {}
void f3(locked_ref<int>::trule const&) {}

int main(int argc, char* argv[])
{
  test t;
  std::cout << "*t.get_value()" << std::endl;
  *t.get_value()=0;

  //self referenceing via get_test, no way to avoid double lock
  std::cout << "*t.get_test()->get_value()" << std::endl;
  *t.get_test()->get_value()=1;

  {
    std::cout << "locked_ref<int> li = t.get_value()" << std::endl;
    //hidden copy constructor wont allow us to use
    //locked_ref<int> li = t.get_value(); syntax
    locked_ref<int> li(t.get_value());
    std::cout << "*li" << std::endl;
    *li=2;
  }

  {
    std::cout << "locked_ref<test> lt = t.get_test()" << std::endl;
    locked_ref<test> lt(t.get_test());
    std::cout << "*lt->get_value()" << std::endl;
    //self reference due to above (li) egt_value() results in double lock
    *lt->get_value()=3;
  }

  std::cout << "f3(t.get_value())" << std::endl;
  f3(t.get_value());
  std::cout << "f2(t.get_test())" << std::endl;
  f2(t.get_test());

  //bug: template param deduction fails
  //std::cout << "f0(t.get_value())" << std::endl;
  //f0(t.get_value());

  {
    std::cout << "locked_ref<int> li = t.get_value()" << std::endl;
    locked_ref<int> li(t.get_value());
    std::cout << "f1(li)" << std::endl;
    f1(li);
    std::cout << "f3(li)" << std::endl;
    f3(li);
    //bug: above gets converted to a trule, trule destructor releases lock
    std::cout << "f3(li)" << std::endl;
    f3(li);
  }

  return 0;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk