sigx++ 2.0.1
|
00001 #ifndef _SIGX_LOCKABLE_H_ 00002 #define _SIGX_LOCKABLE_H_ 00003 00004 /* 00005 * Copyright 2008 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 <sigx/noncopyable.h> 00031 #include <sigx/lockable_fwddecl.h> 00032 #include <sigx/const_trait.h> 00033 #include <sigx/volatile_trait.h> 00034 00035 00036 namespace sigx 00037 { 00038 00050 template<typename T_mutex> 00051 struct lockable_base: noncopyable 00052 { 00053 typedef T_mutex mutex_type; 00054 00055 00056 mutex_type& mutex() const throw() 00057 { 00058 return m_mutex; 00059 } 00060 00061 protected: 00062 lockable_base(): 00063 m_mutex() 00064 {} 00065 00066 00069 mutable mutex_type m_mutex; 00070 }; 00071 00072 00073 00090 template<typename T_type, typename T_mutex> 00091 struct safe_lockable: public lockable_base<T_mutex> 00092 { 00093 // lock_acquirer can use interface methods 00094 template<locking_policy I_policy, typename T_type1, typename T_mutex1, typename T_islockable> friend class lock_acquirer; 00095 00096 typedef lockable_base<T_mutex> parent_type; 00097 // acquired_type = type to protect, 1:1 from T_type 00098 typedef T_type acquired_type; 00099 // volatile_type = make T_type volatile, even if T_type is a reference 00100 // volatile T_type or volatile T_type& 00101 typedef typename volatile_trait<acquired_type>::add volatile_type; 00102 // reference_type = reference to volatile-stripped T_type 00103 // T_type& 00104 typedef typename std::tr1::add_reference<typename volatile_trait<acquired_type>::remove>::type reference_type; 00105 // volatile_reference_type = reference to volatile T_type, even if T_type is a reference 00106 // volatile T_type& 00107 typedef typename std::tr1::add_reference<volatile_type>::type volatile_reference_type; 00108 // reference_type = reference to volatile-stripped T_type, even if T_type is a reference 00109 // const T_type& 00110 typedef typename std::tr1::add_reference<typename const_trait<reference_type>::add>::type const_reference_type; 00111 // cv_reference_type = reference to cv-qualified T_type, even if T_type is a reference 00112 // const volatile T_type& 00113 typedef typename std::tr1::add_reference<typename const_trait<volatile_type>::add>::type cv_reference_type; 00114 // apply const qualifier and reference to toplevel type, unchanged if toplevel type is a reference 00115 typedef typename std::tr1::add_reference<typename std::tr1::add_const<acquired_type>::type>::type toplevel_const_reference_type; 00116 00117 00122 safe_lockable(): 00123 parent_type(), 00124 m_obj() 00125 {} 00126 00129 safe_lockable(toplevel_const_reference_type _a_value): 00130 parent_type(), 00131 m_obj(_a_value) 00132 {} 00133 00134 00135 protected: 00138 volatile_reference_type access_volatile() throw() 00139 { 00140 return m_obj; 00141 } 00142 00145 reference_type access_nonvolatile() throw() 00146 { 00147 // volatile_cast m_obj 00148 return const_cast<reference_type>(m_obj); 00149 } 00150 00153 cv_reference_type access_volatile() const throw() 00154 { 00155 return m_obj; 00156 } 00157 00160 const_reference_type access_nonvolatile() const throw() 00161 { 00162 // volatile_cast m_obj 00163 return const_cast<const_reference_type>(m_obj); 00164 } 00165 00166 00167 private: 00170 volatile_type m_obj; 00171 }; 00172 00173 00176 template<typename T_type, typename T_mutex> 00177 struct lockable: public safe_lockable<T_type, T_mutex> 00178 { 00179 typedef safe_lockable<T_type, T_mutex> parent_type; 00180 typedef typename parent_type::toplevel_const_reference_type toplevel_const_reference_type; 00181 00182 public: 00187 lockable(): 00188 parent_type() 00189 {} 00190 00193 lockable(toplevel_const_reference_type _a_value): 00194 parent_type(_a_value) 00195 {} 00196 00197 // make safe_lockable's interface publicly available 00198 using parent_type::access_volatile; 00199 using parent_type::access_nonvolatile; 00200 }; 00201 00202 00203 00204 #if 0 // specializations for pointers 00205 00214 template<typename T_mutex> 00215 struct lockable<void*, T_mutex>: public lockable_base<T_mutex> 00216 { 00217 typedef void* acquired_type; 00218 typedef T_mutex mutex_type; 00219 typedef lockable_base<mutex_type> parent_type; 00220 typedef lockable<acquired_type, mutex_type> type; 00221 typedef typename volatile_trait<acquired_type>::add volatile_type; 00222 typedef typename std::tr1::add_reference<typename volatile_trait<acquired_type>::remove>::type reference_type; 00223 typedef typename std::tr1::add_reference<typename volatile_trait<acquired_type>::add>::type volatile_reference_type; 00224 typedef typename std::tr1::add_reference<typename std::tr1::add_const<acquired_type>::type>::type take_type; 00225 00226 00231 lockable(take_type _a_value = 0): 00232 parent_type(), 00233 m_obj(_a_value) 00234 {} 00235 00238 volatile_reference_type access_volatile() 00239 { 00240 return m_obj; 00241 } 00242 00245 reference_type access_nonvolatile() 00246 { 00247 // volatile_cast m_obj 00248 return const_cast<reference_type>(m_obj); 00249 } 00250 00251 00252 private: 00255 volatile_type m_obj; 00256 }; 00257 00258 00259 00270 template<typename T_type, typename T_mutex> 00271 struct lockable<T_type*, T_mutex>: public lockable<void*, T_mutex> 00272 { 00273 typedef lockable<void*, T_mutex> parent_type; 00274 typedef T_type* acquired_type; 00275 typedef lockable<acquired_type, mutex_type> type; 00276 typedef typename volatile_trait<acquired_type>::add volatile_type; 00277 typedef typename std::tr1::add_reference<typename volatile_trait<acquired_type>::remove>::type reference_type; 00278 typedef typename std::tr1::add_reference<typename volatile_trait<acquired_type>::add>::type volatile_reference_type; 00279 typedef typename std::tr1::add_reference<typename std::tr1::add_const<acquired_type>::type>::type take_type; 00280 00281 00286 lockable(take_type _a_value = 0): 00287 parent_type((void*&) _a_value) 00288 {} 00289 00295 volatile_reference_type access_volatile() 00296 { 00297 return (volatile_reference_type) parent_type::access_volatile(); 00298 } 00299 00302 reference_type access_acquiree() 00303 { 00304 return (reference_type) parent_type::access_acquiree(); 00305 } 00306 }; 00307 #endif 00308 00309 00310 00311 // @addtogroup threadsafety 00315 } // namespace sigx 00316 00317 00318 #endif // end file guard