sigx++ 2.0.1
|
00001 #ifndef _SIGX_LOCK_ACQUIRER_H_ 00002 #define _SIGX_LOCK_ACQUIRER_H_ 00003 00004 /* 00005 * Copyright 2006 Klaus Triendl 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Library General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public 00018 * License along with this library; if not, write to the Free 00019 * Software Foundation, 51 Franklin Street, Fifth Floor, 00020 * Boston, MA 02110-1301, USA. 00021 */ 00022 00023 /* 00024 * Inspired by Andrei Alexandrescu's article "volatile - Multithreaded 00025 * Programmer's Best Friend": 00026 * http://www.ddj.com/dept/cpp/184403766 00027 */ 00028 00029 #include <tr1/type_traits> 00030 #include <boost/mpl/eval_if.hpp> 00031 #include <boost/mpl/identity.hpp> 00032 #include <sigx/noncopyable.h> 00033 //#include <sigx/nonheapallocatable.h> 00034 #include <sigx/nonpointeraliasing.h> 00035 #include <sigx/lockable_fwddecl.h> 00036 #include <sigx/choose_lock.h> 00037 00038 00039 namespace sigx 00040 { 00041 00087 template<locking_policy I_policy, typename T_type, typename T_mutex, typename T_islockable> 00088 class lock_acquirer: noncopyable/*, nonheapallocatable*/, nonpointeraliasing 00089 { 00090 protected: 00091 typedef T_type acquired_type; 00092 typedef T_mutex mutex_type; 00093 // value_type = acquired_type with top-level reference stripped off 00094 typedef typename std::tr1::remove_reference<acquired_type>::type value_type; 00095 // const_or_value_type = unchanged value_type if policy is writelock, const value_type if readlock 00096 typedef typename boost::mpl::eval_if_c< 00097 I_policy == readlock, 00098 std::tr1::add_const<value_type>, 00099 boost::mpl::identity<value_type> 00100 >::type const_or_value_type; 00101 typedef typename std::tr1::add_reference<typename std::tr1::add_volatile<value_type>::type>::type volatile_reference_type; 00102 typedef typename std::tr1::add_reference<typename std::tr1::remove_volatile<const_or_value_type>::type>::type reference_type; 00103 00109 friend reference_type 00110 access_acquiree(lock_acquirer& l) throw() 00111 { 00112 return l.access_acquiree(); 00113 } 00114 00115 00116 public: 00123 lock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex): 00124 m_lock(_a_mutex), 00125 // volatile_cast 00126 m_acquiree(const_cast<reference_type>(_a_value)) 00127 {} 00132 template<typename T_lockfwd_arg1> 00133 lock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1): 00134 m_lock(_a_mutex, lockfwd_arg1), 00135 // volatile_cast 00136 m_acquiree(const_cast<reference_type>(_a_value)) 00137 {} 00138 00139 00140 protected: 00143 reference_type access_acquiree() throw() 00144 { 00145 return m_acquiree; 00146 } 00147 00148 00149 protected: 00152 typename choose_lock<mutex_type, I_policy>::type m_lock; 00153 00156 reference_type m_acquiree; 00157 }; 00158 00159 00160 00161 template<typename T_type, typename T_mutex, typename T_islockable> 00162 class writelock_acquirer: public lock_acquirer<writelock, T_type, T_mutex, T_islockable> 00163 { 00164 typedef lock_acquirer<writelock, T_type, T_mutex, T_islockable> parent_type; 00165 typedef typename parent_type::mutex_type mutex_type; 00166 typedef typename parent_type::volatile_reference_type volatile_reference_type; 00167 00168 public: 00172 writelock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex): 00173 parent_type(_a_value, _a_mutex) 00174 {} 00179 template<typename T_lockfwd_arg1> 00180 writelock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1): 00181 parent_type(_a_value, _a_mutex, lockfwd_arg1) 00182 {} 00183 }; 00184 00185 template<typename T_type, typename T_mutex, typename T_islockable> 00186 class readlock_acquirer: public lock_acquirer<readlock, T_type, T_mutex, T_islockable> 00187 { 00188 typedef lock_acquirer<readlock, T_type, T_mutex, T_islockable> parent_type; 00189 typedef typename parent_type::mutex_type mutex_type; 00190 typedef typename parent_type::volatile_reference_type volatile_reference_type; 00191 00192 public: 00196 readlock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex): 00197 parent_type(_a_value, _a_mutex) 00198 {} 00203 template<typename T_lockfwd_arg1> 00204 readlock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1): 00205 parent_type(_a_value, _a_mutex, lockfwd_arg1) 00206 {} 00207 }; 00208 00241 template<locking_policy I_policy, typename T_type, typename T_mutex> 00242 class lock_acquirer<I_policy, T_type, T_mutex, std::tr1::true_type>: 00243 // derive from lock_acquirer for the locked type (which is lockable::acquired_type); 00244 public lock_acquirer< 00245 I_policy, 00246 // if the lockable is const ... 00247 typename boost::mpl::eval_if< 00248 std::tr1::is_const<T_type>, 00249 // ... then transfer constness to the type to protect (constness for lockables and the locked type is transitive) 00250 std::tr1::add_const<typename T_type::acquired_type>, 00251 // ... otherwise keep it as specified 00252 boost::mpl::identity<typename T_type::acquired_type> 00253 >::type, 00254 T_mutex 00255 // let compiler deduce whether acquired_type is again a lockable 00256 /*, std::tr1::false_type*/ 00257 > 00258 { 00259 typedef lock_acquirer< 00260 I_policy, 00261 typename boost::mpl::eval_if< 00262 std::tr1::is_const<T_type>, 00263 std::tr1::add_const<typename T_type::acquired_type>, 00264 boost::mpl::identity<typename T_type::acquired_type> 00265 >::type, 00266 T_mutex 00267 /*, std::tr1::false_type*/ 00268 > parent_type; 00269 typedef T_type lockable_type; 00270 00271 00272 public: 00276 explicit lock_acquirer(lockable_type& _a_lockable): 00277 parent_type(_a_lockable.access_volatile(), _a_lockable.mutex()) 00278 {} 00283 template<typename T_lockfwd_arg1> 00284 lock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1): 00285 parent_type(_a_lockable.access_volatile(), _a_lockable.mutex(), lockfwd_arg1) 00286 {} 00287 }; 00288 00289 00292 template<typename T_type, typename T_mutex> 00293 class writelock_acquirer<T_type, T_mutex, std::tr1::true_type>: public lock_acquirer<writelock, T_type, T_mutex, std::tr1::true_type> 00294 { 00295 typedef lock_acquirer<writelock, T_type, T_mutex, std::tr1::true_type> parent_type; 00296 typedef T_type lockable_type; 00297 00298 00299 public: 00303 explicit writelock_acquirer(lockable_type& _a_lockable): 00304 parent_type(_a_lockable) 00305 {} 00310 template<typename T_lockfwd_arg1> 00311 writelock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1): 00312 parent_type(_a_lockable, lockfwd_arg1) 00313 {} 00314 }; 00315 00316 00319 template<typename T_type, typename T_mutex> 00320 class readlock_acquirer<T_type, T_mutex, std::tr1::true_type>: public lock_acquirer<readlock, T_type, T_mutex, std::tr1::true_type> 00321 { 00322 typedef lock_acquirer<readlock, T_type, T_mutex, std::tr1::true_type> parent_type; 00323 typedef T_type lockable_type; 00324 00325 00326 public: 00330 explicit readlock_acquirer(lockable_type& _a_lockable): 00331 parent_type(_a_lockable) 00332 {} 00337 template<typename T_lockfwd_arg1> 00338 readlock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1): 00339 parent_type(_a_lockable, lockfwd_arg1) 00340 {} 00341 }; 00342 00343 00344 // @addtogroup threadsafety 00348 } // namespace mbox 00349 00350 00351 #endif // end file guard