libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/base/threads.hpp
Go to the documentation of this file.
00001 
00026 /*
00027  *  Copyright (C) 2009 Juan Pedro BolĂ­var Puente
00028  *
00029  *  This file is part of Psychosynth.
00030  *   
00031  *  Psychosynth is free software: you can redistribute it and/or modify
00032  *  it under the terms of the GNU General Public License as published by
00033  *  the Free Software Foundation, either version 3 of the License, or
00034  *  (at your option) any later version.
00035  *
00036  *  Psychosynth is distributed in the hope that it will be useful,
00037  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00038  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00039  *  GNU General Public License for more details.
00040  *
00041  *  You should have received a copy of the GNU General Public License
00042  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00043  *
00044  */
00045 
00046 #ifndef PSYNTH_THREADS_H_
00047 #define PSYNTH_THREADS_H_
00048 
00049 #include <cassert>
00050 #include <psynth/base/util.hpp>
00051 
00052 #define PSYNTH_DEFAULT_THREADING         \
00053     psynth::base::default_object_lockable::type
00054 #define PSYNTH_DEFAULT_NONOBJ_THREADING  \
00055     psynth::base::default_class_lockable::type
00056 
00057 #ifndef PSYNTH_DEFAULT_MUTEX
00058 #include <mutex>
00059 #define PSYNTH_DEFAULT_MUTEX             std::recursive_mutex
00060 #endif
00061 
00062 namespace psynth
00063 {
00064 namespace base
00065 {
00066 
00070 template <class Mutex, typename... Args>
00071 std::unique_lock<Mutex> make_unique_lock (Mutex& lock, Args... args)
00072 {
00073     return std::unique_lock<Mutex> (lock, args...);
00074 }
00075 
00083 template <class Mutex = std::mutex>
00084 struct try_lock_guard
00085 {
00086     typedef std::unique_lock<Mutex> guard_type;
00087 
00088     guard_type default_guard ()
00089     { return guard_type (_mutex, std::try_to_lock); }
00090 
00091     template <typename... Args>
00092     guard_type guard (Args... args)
00093     { return guard_type (_mutex, args...); }
00094 
00095     void lock ()
00096     { _mutex.lock (); }
00097 
00098     bool try_lock ()
00099     { return _mutex.try_lock (); }
00100 
00101     void unlock ()
00102     { _mutex.unlock (); }
00103     
00104 private:
00105     Mutex _mutex;
00106 };
00107 
00108 
00112 template <class Mutex = std::mutex>
00113 struct lock_guard : public try_lock_guard<Mutex>
00114 {
00115     typedef std::unique_lock<Mutex> guard_type;
00116     
00117     guard_type default_guard ()
00118     { return guard_type (_mutex); }
00119 
00120 private:
00121     Mutex _mutex;
00122 };
00123 
00124 
00128 template <class Mutex = std::mutex>
00129 struct no_lock_guard
00130 {
00131     struct guard_type
00132     {
00133         bool owns_lock () { return true; }        
00134     };
00135     
00136     guard_type default_guard () { return {}; }
00137     template <typename... Args>
00138     guard_type guard (Args...) { assert (false); return {}; }
00139     void lock () { assert (false); }
00140     bool try_lock () { assert (false); return false; }
00141     void unlock () { assert (false); };
00142 };
00143 
00144 
00145 template <class T>
00146 class no_threading
00147 {
00148 public:
00149     typedef T volatile_type;
00150 
00151     struct lock
00152     {
00153         lock () {}
00154         explicit lock (const no_threading& host) {}
00155         explicit lock (const no_threading* host) {}
00156     };
00157         
00158 private:
00159 };
00160 
00161 template <class T>
00162 class lockable_base
00163 {
00164 public:
00165     typedef volatile T volatile_type;
00166 };
00167 
00168 template <class T, class Mutex = PSYNTH_DEFAULT_MUTEX>
00169 class object_lockable : public lockable_base<T>
00170 {
00171 public:
00172     class lock : public boost::noncopyable
00173     {
00174     public:
00175         lock (const object_lockable& host)
00176             : _host (host)
00177         { _host._mutex.lock (); }
00178 
00179         lock (const object_lockable* host)
00180             : _host (*host)
00181         { _host._mutex.lock (); }
00182         
00183         ~lock ()
00184         { _host._mutex.unlock (); }
00185 
00186     private:
00187         const object_lockable& _host;
00188     };
00189     
00190 private:
00191     mutable Mutex _mutex;
00192 };
00193 
00194 template <class T, class Mutex = PSYNTH_DEFAULT_MUTEX>
00195 class class_lockable : public lockable_base<T>
00196 {
00197 public:
00198     class lock : public boost::noncopyable
00199     {
00200     public:
00201         lock ()
00202         { s_init._mutex.lock (); }
00203 
00204         lock (const class_lockable& host)
00205         { s_init._mutex.lock (); }
00206 
00207         lock (const class_lockable* host)
00208         { s_init._mutex.lock (); }
00209         
00210         ~lock ()
00211         { s_init._mutex.unlock (); }
00212     };
00213         
00214 private:
00215     struct initializer
00216     {
00217         bool  _is_init;
00218         Mutex _mutex;
00219 
00220         initializer ()
00221             : _is_init (false)
00222         { _is_init = true; }
00223 
00224         ~initializer ()
00225         { assert (_is_init); }
00226     };
00227 
00228     static initializer s_init;
00229 };
00230 
00231 template<class T, class M>
00232 typename class_lockable<T, M>::initializer class_lockable<T, M>::s_init;
00233 
00234 typedef
00235 tpl_bind_snd<object_lockable, PSYNTH_DEFAULT_MUTEX>
00236 default_object_lockable;
00237 
00238 typedef
00239 tpl_bind_snd<class_lockable, PSYNTH_DEFAULT_MUTEX>
00240 default_class_lockable;
00241 
00242 } /* namespace base */
00243 } /* namespace psynth */
00244 
00245 #endif /* PSYNTH_THREADS_H_ */