1 // (C) Copyright 2012 Vicente J. Botet Escriba 2 // Distributed under the Boost Software License, Version 1.0. (See 3 // accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 7 #ifndef BOOST_THREAD_EXTERNALLY_LOCKED_HPP 8 #define BOOST_THREAD_EXTERNALLY_LOCKED_HPP 9 10 #include <boost/thread/detail/config.hpp> 11 12 #include <boost/thread/exceptions.hpp> 13 #include <boost/thread/lock_concepts.hpp> 14 #include <boost/thread/lock_traits.hpp> 15 #include <boost/thread/lockable_concepts.hpp> 16 #include <boost/thread/strict_lock.hpp> 17 18 #include <boost/static_assert.hpp> 19 #include <boost/type_traits/is_same.hpp> 20 #include <boost/throw_exception.hpp> 21 #include <boost/core/swap.hpp> 22 23 #include <boost/config/abi_prefix.hpp> 24 25 namespace boost 26 { 27 class mutex; 28 29 /** 30 * externally_locked cloaks an object of type T, and actually provides full 31 * access to that object through the get and set member functions, provided you 32 * pass a reference to a strict lock object 33 */ 34 35 //[externally_locked 36 template <typename T, typename MutexType = boost::mutex> 37 class externally_locked; 38 template <typename T, typename MutexType> 39 class externally_locked 40 { 41 //BOOST_CONCEPT_ASSERT(( CopyConstructible<T> )); 42 BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> )); 43 44 public: 45 typedef MutexType mutex_type; 46 47 BOOST_THREAD_COPYABLE_AND_MOVABLE( externally_locked ) 48 /** 49 * Requires: T is a model of CopyConstructible. 50 * Effects: Constructs an externally locked object copying the cloaked type. 51 */ externally_locked(mutex_type & mtx,const T & obj)52 externally_locked(mutex_type& mtx, const T& obj) : 53 obj_(obj), mtx_(&mtx) 54 { 55 } 56 57 /** 58 * Requires: T is a model of Movable. 59 * Effects: Constructs an externally locked object by moving the cloaked type. 60 */ externally_locked(mutex_type & mtx,BOOST_THREAD_RV_REF (T)obj)61 externally_locked(mutex_type& mtx, BOOST_THREAD_RV_REF(T) obj) : 62 obj_(move(obj)), mtx_(&mtx) 63 { 64 } 65 66 /** 67 * Requires: T is a model of DefaultConstructible. 68 * Effects: Constructs an externally locked object initializing the cloaked type with the default constructor. 69 */ externally_locked(mutex_type & mtx)70 externally_locked(mutex_type& mtx) // BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T())) 71 : obj_(), mtx_(&mtx) 72 { 73 } 74 75 /** 76 * Copy constructor 77 */ externally_locked(externally_locked const & rhs)78 externally_locked(externally_locked const& rhs) //BOOST_NOEXCEPT 79 : obj_(rhs.obj_), mtx_(rhs.mtx_) 80 { 81 } 82 /** 83 * Move constructor 84 */ externally_locked(BOOST_THREAD_RV_REF (externally_locked)rhs)85 externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) //BOOST_NOEXCEPT 86 : obj_(move(rhs.obj_)), mtx_(rhs.mtx_) 87 { 88 } 89 90 /// assignment operator =(externally_locked const & rhs)91 externally_locked& operator=(externally_locked const& rhs) //BOOST_NOEXCEPT 92 { 93 obj_=rhs.obj_; 94 mtx_=rhs.mtx_; 95 return *this; 96 } 97 98 /// move assignment operator =(BOOST_THREAD_RV_REF (externally_locked)rhs)99 externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) // BOOST_NOEXCEPT 100 { 101 obj_=move(BOOST_THREAD_RV(rhs).obj_); 102 mtx_=rhs.mtx_; 103 return *this; 104 } 105 swap(externally_locked & rhs)106 void swap(externally_locked& rhs) //BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR) 107 { 108 swap(obj_, rhs.obj_); 109 swap(mtx_, rhs.mtx_); 110 } 111 112 /** 113 * Requires: The lk parameter must be locking the associated mtx. 114 * 115 * Returns: The address of the cloaked object.. 116 * 117 * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions 118 */ get(strict_lock<mutex_type> & lk)119 T& get(strict_lock<mutex_type>& lk) 120 { 121 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 122 return obj_; 123 } 124 get(strict_lock<mutex_type> & lk) const125 const T& get(strict_lock<mutex_type>& lk) const 126 { 127 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 128 return obj_; 129 } 130 131 template <class Lock> get(nested_strict_lock<Lock> & lk)132 T& get(nested_strict_lock<Lock>& lk) 133 { 134 BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ 135 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 136 return obj_; 137 } 138 139 template <class Lock> get(nested_strict_lock<Lock> & lk) const140 const T& get(nested_strict_lock<Lock>& lk) const 141 { 142 BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ 143 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 144 return obj_; 145 } 146 147 /** 148 * Requires: The lk parameter must be locking the associated mtx. 149 * Returns: The address of the cloaked object.. 150 * 151 * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions 152 */ 153 template <class Lock> get(Lock & lk)154 T& get(Lock& lk) 155 { 156 BOOST_CONCEPT_ASSERT(( StrictLock<Lock> )); 157 BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/ 158 BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ 159 160 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 161 162 return obj_; 163 } 164 mutex() const165 mutex_type* mutex() const BOOST_NOEXCEPT 166 { 167 return mtx_; 168 } 169 170 // modifiers 171 lock()172 void lock() 173 { 174 mtx_->lock(); 175 } unlock()176 void unlock() 177 { 178 mtx_->unlock(); 179 } try_lock()180 bool try_lock() 181 { 182 return mtx_->try_lock(); 183 } 184 // todo add time related functions 185 186 private: 187 T obj_; 188 mutex_type* mtx_; 189 }; 190 //] 191 192 /** 193 * externally_locked<T&,M> specialization for T& that cloaks an reference to an object of type T, and actually 194 * provides full access to that object through the get and set member functions, provided you 195 * pass a reference to a strict lock object. 196 */ 197 198 //[externally_locked_ref 199 template <typename T, typename MutexType> 200 class externally_locked<T&, MutexType> 201 { 202 //BOOST_CONCEPT_ASSERT(( CopyConstructible<T> )); 203 BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> )); 204 205 public: 206 typedef MutexType mutex_type; 207 208 BOOST_THREAD_COPYABLE_AND_MOVABLE( externally_locked ) 209 210 /** 211 * Effects: Constructs an externally locked object storing the cloaked reference object. 212 */ externally_locked(T & obj,mutex_type & mtx)213 externally_locked(T& obj, mutex_type& mtx) BOOST_NOEXCEPT : 214 obj_(&obj), mtx_(&mtx) 215 { 216 } 217 218 /// copy constructor externally_locked(externally_locked const & rhs)219 externally_locked(externally_locked const& rhs) BOOST_NOEXCEPT : 220 obj_(rhs.obj_), mtx_(rhs.mtx_) 221 { 222 } 223 224 /// move constructor externally_locked(BOOST_THREAD_RV_REF (externally_locked)rhs)225 externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) BOOST_NOEXCEPT : 226 obj_(rhs.obj_), mtx_(rhs.mtx_) 227 { 228 } 229 230 /// assignment operator =(externally_locked const & rhs)231 externally_locked& operator=(externally_locked const& rhs) BOOST_NOEXCEPT 232 { 233 obj_=rhs.obj_; 234 mtx_=rhs.mtx_; 235 return *this; 236 } 237 238 /// move assignment operator =(BOOST_THREAD_RV_REF (externally_locked)rhs)239 externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) BOOST_NOEXCEPT 240 { 241 obj_=rhs.obj_; 242 mtx_=rhs.mtx_; 243 return *this; 244 } 245 swap(externally_locked & rhs)246 void swap(externally_locked& rhs) BOOST_NOEXCEPT 247 { 248 swap(obj_, rhs.obj_); 249 swap(mtx_, rhs.mtx_); 250 } 251 /** 252 * Requires: The lk parameter must be locking the associated mtx. 253 * 254 * Returns: The address of the cloaked object.. 255 * 256 * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions 257 */ get(strict_lock<mutex_type> const & lk)258 T& get(strict_lock<mutex_type> const& lk) 259 { 260 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 261 return *obj_; 262 } 263 get(strict_lock<mutex_type> const & lk) const264 const T& get(strict_lock<mutex_type> const& lk) const 265 { 266 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 267 return *obj_; 268 } 269 270 template <class Lock> get(nested_strict_lock<Lock> const & lk)271 T& get(nested_strict_lock<Lock> const& lk) 272 { 273 BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ 274 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 275 return *obj_; 276 } 277 278 template <class Lock> get(nested_strict_lock<Lock> const & lk) const279 const T& get(nested_strict_lock<Lock> const& lk) const 280 { 281 BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ 282 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 283 return *obj_; 284 } 285 286 /** 287 * Requires: The lk parameter must be locking the associated mtx. 288 * Returns: The address of the cloaked object.. 289 * 290 * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions 291 */ 292 template <class Lock> get(Lock const & lk)293 T& get(Lock const& lk) 294 { 295 BOOST_CONCEPT_ASSERT(( StrictLock<Lock> )); 296 BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/ 297 BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ 298 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 299 return *obj_; 300 } 301 302 /** 303 * Requires: The lk parameter must be locking the associated mtx. 304 * Returns: The address of the cloaked object.. 305 * 306 * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions 307 */ 308 template <class Lock> get(Lock const & lk) const309 T const& get(Lock const& lk) const 310 { 311 BOOST_CONCEPT_ASSERT(( StrictLock<Lock> )); 312 BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/ 313 BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ 314 BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ 315 return *obj_; 316 } mutex() const317 mutex_type* mutex() const BOOST_NOEXCEPT 318 { 319 return mtx_; 320 } 321 lock()322 void lock() 323 { 324 mtx_->lock(); 325 } unlock()326 void unlock() 327 { 328 mtx_->unlock(); 329 } try_lock()330 bool try_lock() 331 { 332 return mtx_->try_lock(); 333 } 334 // todo add time related functions 335 336 protected: 337 T* obj_; 338 mutex_type* mtx_; 339 }; 340 //] 341 342 template <typename T, typename MutexType> swap(externally_locked<T,MutexType> & lhs,externally_locked<T,MutexType> & rhs)343 void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs) // BOOST_NOEXCEPT 344 { 345 lhs.swap(rhs); 346 } 347 348 } 349 350 #include <boost/config/abi_suffix.hpp> 351 352 #endif // header 353