1 // (C) Copyright 2012 Vicente Botet 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #ifndef BOOST_THREAD_LOCK_CONCEPTS_HPP 7 #define BOOST_THREAD_LOCK_CONCEPTS_HPP 8 9 #include <boost/thread/lock_traits.hpp> 10 #include <boost/thread/lock_options.hpp> 11 #include <boost/thread/lockable_concepts.hpp> 12 #include <boost/thread/exceptions.hpp> 13 #include <boost/thread/detail/move.hpp> 14 15 #include <boost/chrono/chrono.hpp> 16 #include <boost/concept_check.hpp> 17 #include <boost/static_assert.hpp> 18 19 namespace boost 20 { 21 22 /** 23 * BasicLock object supports the basic features 24 * required to delimit a critical region 25 * Supports the basic lock, unlock and try_lock functions and 26 * defines the lock traits 27 */ 28 29 template <typename Lk> 30 struct BasicLock 31 { 32 typedef typename Lk::mutex_type mutex_type; cvt_mutex_ptrboost::BasicLock33 void cvt_mutex_ptr(mutex_type*) {} 34 BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> )); 35 BOOST_CONCEPT_USAGEboost::BasicLock36 BOOST_CONCEPT_USAGE(BasicLock) 37 { 38 const Lk l1(mtx); 39 Lk l2(mtx, defer_lock); 40 Lk l3(mtx, adopt_lock); 41 Lk l4(( Lk())); 42 Lk l5(( boost::move(l2))); 43 cvt_mutex_ptr(l1.mutex()); 44 if (l1.owns_lock()) return; 45 if (l1) return; 46 if (!l1) return; 47 48 l2.lock(); 49 l2.unlock(); 50 l2.release(); 51 52 } BasicLockboost::BasicLock53 BasicLock() : 54 mtx(*static_cast<mutex_type*>(0)) 55 {} 56 private: 57 BasicLock operator=(BasicLock const&); 58 mutex_type& mtx; 59 } 60 ; 61 62 template <typename Lk> 63 struct Lock 64 { 65 BOOST_CONCEPT_ASSERT(( BasicLock<Lk> )); 66 typedef typename Lk::mutex_type mutex_type; 67 BOOST_CONCEPT_ASSERT(( Lockable<mutex_type> )); 68 BOOST_CONCEPT_USAGEboost::Lock69 BOOST_CONCEPT_USAGE(Lock) 70 { 71 Lk l1(mtx, try_to_lock); 72 if (l1.try_lock()) return; 73 } Lockboost::Lock74 Lock() : 75 mtx(*static_cast<mutex_type*>(0)) 76 {} 77 private: 78 Lock operator=(Lock const&); 79 mutex_type& mtx; 80 }; 81 82 template <typename Lk> 83 struct TimedLock 84 { 85 BOOST_CONCEPT_ASSERT(( Lock<Lk> )); 86 typedef typename Lk::mutex_type mutex_type; 87 BOOST_CONCEPT_ASSERT(( TimedLockable<mutex_type> )); 88 BOOST_CONCEPT_USAGEboost::TimedLock89 BOOST_CONCEPT_USAGE(TimedLock) 90 { 91 const Lk l1(mtx, t); 92 Lk l2(mtx, d); 93 if (l1.try_lock_until(t)) return; 94 if (l1.try_lock_for(d)) return; 95 } TimedLockboost::TimedLock96 TimedLock() : 97 mtx(*static_cast<mutex_type*>(0)) 98 {} 99 private: 100 TimedLock operator=(TimedLock const&); 101 mutex_type& mtx; 102 boost::chrono::system_clock::time_point t; 103 boost::chrono::system_clock::duration d; 104 }; 105 106 template <typename Lk> 107 struct UniqueLock 108 { 109 BOOST_CONCEPT_ASSERT(( TimedLock<Lk> )); 110 typedef typename Lk::mutex_type mutex_type; 111 BOOST_CONCEPT_USAGEboost::UniqueLock112 BOOST_CONCEPT_USAGE(UniqueLock) 113 { 114 115 } UniqueLockboost::UniqueLock116 UniqueLock() : 117 mtx(*static_cast<mutex_type*>(0)) 118 {} 119 private: 120 UniqueLock operator=(UniqueLock const&); 121 mutex_type& mtx; 122 }; 123 124 template <typename Lk> 125 struct SharedLock 126 { 127 BOOST_CONCEPT_ASSERT(( TimedLock<Lk> )); 128 typedef typename Lk::mutex_type mutex_type; 129 BOOST_CONCEPT_USAGEboost::SharedLock130 BOOST_CONCEPT_USAGE(SharedLock) 131 { 132 } SharedLockboost::SharedLock133 SharedLock() : 134 mtx(*static_cast<mutex_type*>(0)) 135 {} 136 private: 137 SharedLock operator=(SharedLock const&); 138 mutex_type& mtx; 139 140 }; 141 142 template <typename Lk> 143 struct UpgradeLock 144 { 145 BOOST_CONCEPT_ASSERT(( SharedLock<Lk> )); 146 typedef typename Lk::mutex_type mutex_type; 147 BOOST_CONCEPT_USAGEboost::UpgradeLock148 BOOST_CONCEPT_USAGE(UpgradeLock) 149 { 150 } UpgradeLockboost::UpgradeLock151 UpgradeLock() : 152 mtx(*static_cast<mutex_type*>(0)) 153 {} 154 private: 155 UpgradeLock operator=(UpgradeLock const&); 156 mutex_type& mtx; 157 }; 158 159 /** 160 * An StrictLock is a scoped lock guard ensuring the mutex is locked on the 161 * scope of the lock, by locking the mutex on construction and unlocking it on 162 * destruction. 163 * 164 * Essentially, a StrictLock's role is only to live on the stack as an 165 * automatic variable. strict_lock must adhere to a non-copy and non-alias 166 * policy. StrictLock disables copying by making the copy constructor and the 167 * assignment operator private. While we're at it, let's disable operator new 168 * and operator delete; strict locks are not intended to be allocated on the 169 * heap. StrictLock avoids aliasing by using a slightly less orthodox and 170 * less well-known technique: disable address taking. 171 */ 172 173 template <typename Lk> 174 struct StrictLock 175 { 176 typedef typename Lk::mutex_type mutex_type; 177 BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> )); 178 BOOST_STATIC_ASSERT(( is_strict_lock<Lk>::value )); 179 BOOST_CONCEPT_USAGEboost::StrictLock180 BOOST_CONCEPT_USAGE( StrictLock) 181 { 182 if (l1.owns_lock(&mtx)) return; 183 } StrictLockboost::StrictLock184 StrictLock() : 185 l1(*static_cast<Lk*>(0)), 186 mtx(*static_cast<mutex_type*>(0)) 187 {} 188 private: 189 StrictLock operator=(StrictLock const&); 190 191 Lk const& l1; 192 mutex_type const& mtx; 193 194 }; 195 196 } 197 #endif 198