lock_acquirer.h

Go to the documentation of this file.
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

Generated on Wed Jan 28 21:37:59 2009 for sigx++ by  doxygen 1.5.8