1 /* 2 * Copyright Andrey Semashev 2007 - 2015. 3 * Distributed under the Boost Software License, Version 1.0. 4 * (See accompanying file LICENSE_1_0.txt or copy at 5 * http://www.boost.org/LICENSE_1_0.txt) 6 */ 7 /*! 8 * \file locks.hpp 9 * \author Andrey Semashev 10 * \date 30.05.2010 11 * 12 * \brief This header is the Boost.Log library implementation, see the library documentation 13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. 14 */ 15 16 #ifndef BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_ 17 #define BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_ 18 19 #include <boost/log/detail/config.hpp> 20 #include <boost/log/detail/header.hpp> 21 22 #ifdef BOOST_HAS_PRAGMA_ONCE 23 #pragma once 24 #endif 25 26 namespace boost { 27 28 #ifndef BOOST_LOG_NO_THREADS 29 30 // Forward declaration of Boost.Thread locks. Specified here to avoid including Boost.Thread, 31 // which would bring in many dependent headers, including a great deal of Boost.DateTime. 32 template< typename > 33 class lock_guard; 34 template< typename > 35 class shared_lock_guard; 36 template< typename > 37 class shared_lock; 38 template< typename > 39 class upgrade_lock; 40 template< typename > 41 class unique_lock; 42 43 template< typename > 44 struct is_mutex_type; 45 46 #endif // BOOST_LOG_NO_THREADS 47 48 BOOST_LOG_OPEN_NAMESPACE 49 50 //! An auxiliary pseudo-lock to express no locking requirements in logger features 51 template< typename MutexT > 52 class no_lock 53 { 54 public: 55 /*! 56 * Constructs the pseudo-lock. The mutex is not affected during the construction. 57 */ no_lock(MutexT &)58 explicit no_lock(MutexT&) BOOST_NOEXCEPT {} 59 60 private: 61 no_lock(no_lock const&); 62 no_lock& operator= (no_lock const&); 63 }; 64 65 namespace aux { 66 67 #ifndef BOOST_LOG_NO_THREADS 68 69 //! A trait to detect if the mutex supports exclusive locking 70 template< typename MutexT > 71 struct is_exclusively_lockable 72 { 73 typedef char true_type; 74 struct false_type { char t[2]; }; 75 76 template< typename T > 77 static true_type check_lockable(T*, void (T::*)() = &T::lock, void (T::*)() = &T::unlock); 78 static false_type check_lockable(void*); 79 80 enum value_t { value = sizeof(check_lockable((MutexT*)NULL)) == sizeof(true_type) }; 81 }; 82 83 //! A trait to detect if the mutex supports shared locking 84 template< typename MutexT > 85 struct is_shared_lockable 86 { 87 typedef char true_type; 88 struct false_type { char t[2]; }; 89 90 template< typename T > 91 static true_type check_shared_lockable(T*, void (T::*)() = &T::lock_shared, void (T::*)() = &T::unlock_shared); 92 static false_type check_shared_lockable(void*); 93 94 enum value_t { value = sizeof(check_shared_lockable((MutexT*)NULL)) == sizeof(true_type) }; 95 }; 96 97 //! A scope guard that automatically unlocks the mutex on destruction 98 template< typename MutexT > 99 struct exclusive_auto_unlocker 100 { exclusive_auto_unlockerboost::aux::exclusive_auto_unlocker101 explicit exclusive_auto_unlocker(MutexT& m) BOOST_NOEXCEPT : m_Mutex(m) 102 { 103 } ~exclusive_auto_unlockerboost::aux::exclusive_auto_unlocker104 ~exclusive_auto_unlocker() 105 { 106 m_Mutex.unlock(); 107 } 108 109 BOOST_DELETED_FUNCTION(exclusive_auto_unlocker(exclusive_auto_unlocker const&)) 110 BOOST_DELETED_FUNCTION(exclusive_auto_unlocker& operator= (exclusive_auto_unlocker const&)) 111 112 protected: 113 MutexT& m_Mutex; 114 }; 115 116 //! An analogue to the minimalistic \c lock_guard template. Defined here to avoid including Boost.Thread. 117 template< typename MutexT > 118 struct exclusive_lock_guard 119 { 120 explicit exclusive_lock_guard(MutexT& m) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m.lock())) : m_Mutex(m) 121 { 122 m.lock(); 123 } ~exclusive_lock_guardboost::aux::exclusive_lock_guard124 ~exclusive_lock_guard() 125 { 126 m_Mutex.unlock(); 127 } 128 129 BOOST_DELETED_FUNCTION(exclusive_lock_guard(exclusive_lock_guard const&)) 130 BOOST_DELETED_FUNCTION(exclusive_lock_guard& operator= (exclusive_lock_guard const&)) 131 132 private: 133 MutexT& m_Mutex; 134 }; 135 136 //! An analogue to the minimalistic \c lock_guard template that locks \c shared_mutex with shared ownership. 137 template< typename MutexT > 138 struct shared_lock_guard 139 { 140 explicit shared_lock_guard(MutexT& m) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m.lock_shared())) : m_Mutex(m) 141 { 142 m.lock_shared(); 143 } ~shared_lock_guardboost::aux::shared_lock_guard144 ~shared_lock_guard() 145 { 146 m_Mutex.unlock_shared(); 147 } 148 149 BOOST_DELETED_FUNCTION(shared_lock_guard(shared_lock_guard const&)) 150 BOOST_DELETED_FUNCTION(shared_lock_guard& operator= (shared_lock_guard const&)) 151 152 private: 153 MutexT& m_Mutex; 154 }; 155 156 //! A deadlock-safe lock type that exclusively locks two mutexes 157 template< typename MutexT1, typename MutexT2 > 158 class multiple_unique_lock2 159 { 160 public: multiple_unique_lock2(MutexT1 & m1,MutexT2 & m2)161 multiple_unique_lock2(MutexT1& m1, MutexT2& m2) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.lock()) && BOOST_NOEXCEPT_EXPR(m2.lock())) : 162 m_p1(&m1), 163 m_p2(&m2) 164 { 165 // Yes, it's not conforming, but it works 166 // and it doesn't require to #include <functional> 167 if (static_cast< void* >(m_p1) < static_cast< void* >(m_p2)) 168 { 169 m_p1->lock(); 170 m_p2->lock(); 171 } 172 else 173 { 174 m_p2->lock(); 175 m_p1->lock(); 176 } 177 } ~multiple_unique_lock2()178 ~multiple_unique_lock2() 179 { 180 m_p2->unlock(); 181 m_p1->unlock(); 182 } 183 184 private: 185 MutexT1* m_p1; 186 MutexT2* m_p2; 187 }; 188 189 #endif // BOOST_LOG_NO_THREADS 190 191 } // namespace aux 192 193 BOOST_LOG_CLOSE_NAMESPACE // namespace log 194 195 } // namespace boost 196 197 #include <boost/log/detail/footer.hpp> 198 199 #endif // BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_ 200