libmoost
/home/mhx/git/github/libmoost/include/moost/thread/token_mutex.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #ifndef MOOST_THREAD_TOKEN_MUTEX_H__
00029 #define MOOST_THREAD_TOKEN_MUTEX_H__
00030 
00031 #include <set>
00032 #include <boost/thread/condition.hpp>
00033 #include <boost/thread/mutex.hpp>
00034 
00035 namespace moost { namespace thread {
00036 
00041 template<typename T>
00042 class token_mutex
00043 {
00044 private:
00045 
00046    boost::mutex m_mutex;
00047    boost::condition m_cond;
00048    std::set<T> m_tokens;
00049    bool m_full_lock;
00050 
00051 public:
00052    class scoped_promote_lock;
00053 
00057    class scoped_lock
00058    {
00059    private:
00060       token_mutex<T>& m_token_mutex;
00061       T m_token;
00062 
00063       friend class scoped_promote_lock;
00064    public:
00065       scoped_lock( token_mutex<T> & token_mutex,
00066                    const T & token )
00067          : m_token_mutex(token_mutex),
00068          m_token(token)
00069       {
00070          m_token_mutex.lock(m_token);
00071       }
00072       ~scoped_lock()
00073       {
00074          m_token_mutex.unlock(m_token);
00075       }
00076    };
00077 
00081   class scoped_try_lock
00082   {
00083   private:
00084      token_mutex<T>& m_token_mutex;
00085      T m_token;
00086      bool m_got_lock;
00087   public:
00088      scoped_try_lock( token_mutex<T> & token_mutex,
00089                       const T & token )
00090         : m_token_mutex(token_mutex),
00091         m_token(token)
00092      {
00093         m_got_lock = m_token_mutex.trylock(m_token);
00094      }
00095      operator bool () const { return m_got_lock; }
00096      bool operator ! () const { return !m_got_lock; }
00097      ~scoped_try_lock()
00098      {
00099         if (m_got_lock)
00100            m_token_mutex.unlock(m_token);
00101      }
00102   };
00103 
00107   class scoped_full_lock
00108   {
00109   private:
00110      token_mutex<T>& m_token_mutex;
00111   public:
00112      scoped_full_lock(token_mutex<T> & token_mutex)
00113         : m_token_mutex(token_mutex)
00114      {
00115         m_token_mutex.full_lock();
00116      }
00117      ~scoped_full_lock()
00118      {
00119         m_token_mutex.full_unlock();
00120      }
00121   };
00122 
00126   class scoped_promote_lock
00127   {
00128   private:
00129      token_mutex<T>& m_token_mutex;
00130   public:
00131      scoped_promote_lock(scoped_lock& lock)
00132         : m_token_mutex(lock.m_token_mutex)
00133      {
00134         m_token_mutex.unlock(lock.m_token);
00135         m_token_mutex.full_lock();
00136      }
00137 
00138      ~scoped_promote_lock()
00139      {
00140         m_token_mutex.full_unlock();
00141      }
00142   };
00143 
00147   token_mutex() : m_full_lock(false) {}
00148 
00152   void lock(const T& token)
00153   {
00154      boost::mutex::scoped_lock lock(m_mutex);
00155      while (m_tokens.find(token) != m_tokens.end() || m_full_lock)
00156         m_cond.wait(lock);
00157      m_tokens.insert(token);
00158   }
00159 
00163   void unlock(const T& token)
00164   {
00165      boost::mutex::scoped_lock lock(m_mutex);
00166      m_tokens.erase(token);
00167      m_cond.notify_all();
00168   }
00169 
00173   void full_lock()
00174   {
00175      boost::mutex::scoped_lock lock(m_mutex);
00176      m_full_lock = true;
00177      while (!m_tokens.empty())
00178         m_cond.wait(lock);
00179   }
00180 
00184   void full_unlock()
00185   {
00186      boost::mutex::scoped_lock lock(m_mutex);
00187      m_full_lock = false;
00188      m_cond.notify_all();
00189   }
00190 
00197   bool trylock(const T& token)
00198   {
00199      boost::mutex::scoped_lock lock(m_mutex);
00200      if (m_tokens.find(token) == m_tokens.end() && !m_full_lock)
00201      {
00202         m_tokens.insert(token);
00203         return true;
00204      }
00205      return false;
00206   }
00207 };
00208 
00209 }} // moost::thread
00210 
00211 #endif // MOOST_THREAD_TOKEN_MUTEX_H__