Protecting the interface of a singleton class

posted Mar 27, 2012, 9:42 PM by Nico Kruithof
This is quite a long code snippet. It can be used to easily lock an interface of a class. The key observation are the read_lock() and write_lock() functions that are static. They can therefore be used as functions to get default arguments.

#include <tbb/spin_rw_mutex.h>
#include <boost/shared_ptr.hpp>

class ProtectedClass
{
public:
  class ReadLock
  {
    friend class ProtectedClass;
  private:
    ReadLock(tbb::spin_rw_mutex &mutex)
      : m_lock(new tbb::spin_rw_mutex::scoped_lock(mutex, /*writer*/ false))
    {
    }
  protected:
    ReadLock(tbb::spin_rw_mutex &mutex, bool is_writer)
      : m_lock(new tbb::spin_rw_mutex::scoped_lock(mutex, is_writer))
    {
    }
    
    boost::shared_ptr<tbb::spin_rw_mutex::scoped_lock> m_lock;
  };
  class WriteLock : public ReadLock
  {
    friend class ProtectedClass;
  private:
    WriteLock(tbb::spin_rw_mutex &mutex)
      : ReadLock(mutex, true)
    {
    }
  };

  static ProtectedClass &get()
  {
    static ProtectedClass instance;
    return instance;
  }
  
  static ReadLock read_lock() { return ReadLock(ProtectedClass::get().m_mutex); }
  static WriteLock write_lock() { return WriteLock(ProtectedClass::get().m_mutex); }

  bool read_function1(const ReadLock &lock = read_lock()) { return read_function2(lock); }
  bool read_function2(const ReadLock &lock = read_lock()) { return true; }
  bool write_function1(const WriteLock &lock = write_lock()) { return read_function1(lock) && write_function2(lock); }
  bool write_function2(const WriteLock &lock = write_lock()) { return true; }

private:
  tbb::spin_rw_mutex m_mutex;
};

int main() {
  ProtectedClass &sm = ProtectedClass::get();
  {
    sm.read_function1();
  }

  {
    ProtectedClass::ReadLock read_lock = sm.read_lock();
    sm.read_function1(read_lock);
  }
  {
    ProtectedClass::WriteLock write_lock = sm.write_lock();
    sm.write_function1(write_lock);
  }
}
#include <tbb/spin_rw_mutex.h>
#include <boost/shared_ptr.hpp>

class SceneManager
{
public:
  class ReadLock
  {
    friend class SceneManager;
  private:
    ReadLock(tbb::spin_rw_mutex &mutex)
      : m_lock(new tbb::spin_rw_mutex::scoped_lock(mutex, /*writer*/ false))
    {
    }
  protected:
    ReadLock(tbb::spin_rw_mutex &mutex, bool is_writer)
      : m_lock(new tbb::spin_rw_mutex::scoped_lock(mutex, is_writer))
    {
    }
    
    boost::shared_ptr<tbb::spin_rw_mutex::scoped_lock> m_lock;
  };
  class WriteLock : public ReadLock
  {
    friend class SceneManager;
  private:
    WriteLock(tbb::spin_rw_mutex &mutex)
      : ReadLock(mutex, true)
    {
    }
  };

  static SceneManager &get()
  {
    static SceneManager instance;
    return instance;
  }
  
  static ReadLock read_lock() { return ReadLock(SceneManager::get().m_mutex); }
  static WriteLock write_lock() { return WriteLock(SceneManager::get().m_mutex); }

  bool read_function1(const ReadLock &lock = read_lock()) { return read_function2(lock); }
  bool read_function2(const ReadLock &lock = read_lock()) { return true; }
  bool write_function1(const WriteLock &lock = write_lock()) { return read_function1(lock) && write_function2(lock); }
  bool write_function2(const WriteLock &lock = write_lock()) { return true; }

private:
  tbb::spin_rw_mutex m_mutex;
};

int main() {
  SceneManager &sm = SceneManager::get();
  {
    sm.read_function1();
  }

  {
    SceneManager::ReadLock read_lock = sm.read_lock();
    sm.read_function1(read_lock);
  }
  {
    SceneManager::WriteLock write_lock = sm.write_lock();
    sm.write_function1(write_lock);
  }
}

Comments