1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2017 - ROLI Ltd. 6 7 JUCE is an open source library subject to commercial or open-source 8 licensing. 9 10 The code included in this file is provided under the terms of the ISC license 11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission 12 To use, copy, modify, and/or distribute this software for any purpose with or 13 without fee is hereby granted provided that the above copyright notice and 14 this permission notice appear in all copies. 15 16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 18 DISCLAIMED. 19 20 ============================================================================== 21 */ 22 23 namespace juce 24 { 25 26 //============================================================================== 27 /** 28 Automatically locks and unlocks a mutex object. 29 30 Use one of these as a local variable to provide RAII-based locking of a mutex. 31 32 The templated class could be a CriticalSection, SpinLock, or anything else that 33 provides enter() and exit() methods. 34 35 e.g. @code 36 CriticalSection myCriticalSection; 37 38 for (;;) 39 { 40 const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection); 41 // myCriticalSection is now locked 42 43 ...do some stuff... 44 45 // myCriticalSection gets unlocked here. 46 } 47 @endcode 48 49 @see GenericScopedUnlock, CriticalSection, SpinLock, ScopedLock, ScopedUnlock 50 51 @tags{Core} 52 */ 53 template <class LockType> 54 class GenericScopedLock 55 { 56 public: 57 //============================================================================== 58 /** Creates a GenericScopedLock. 59 60 As soon as it is created, this will acquire the lock, and when the GenericScopedLock 61 object is deleted, the lock will be released. 62 63 Make sure this object is created and deleted by the same thread, 64 otherwise there are no guarantees what will happen! Best just to use it 65 as a local stack object, rather than creating one with the new() operator. 66 */ GenericScopedLock(const LockType & lock)67 inline explicit GenericScopedLock (const LockType& lock) noexcept : lock_ (lock) { lock.enter(); } 68 69 /** Destructor. 70 The lock will be released when the destructor is called. 71 Make sure this object is created and deleted by the same thread, otherwise there are 72 no guarantees what will happen! 73 */ ~GenericScopedLock()74 inline ~GenericScopedLock() noexcept { lock_.exit(); } 75 76 private: 77 //============================================================================== 78 const LockType& lock_; 79 80 JUCE_DECLARE_NON_COPYABLE (GenericScopedLock) 81 }; 82 83 84 //============================================================================== 85 /** 86 Automatically unlocks and re-locks a mutex object. 87 88 This is the reverse of a GenericScopedLock object - instead of locking the mutex 89 for the lifetime of this object, it unlocks it. 90 91 Make sure you don't try to unlock mutexes that aren't actually locked! 92 93 e.g. @code 94 95 CriticalSection myCriticalSection; 96 97 for (;;) 98 { 99 const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection); 100 // myCriticalSection is now locked 101 102 ... do some stuff with it locked .. 103 104 while (xyz) 105 { 106 ... do some stuff with it locked .. 107 108 const GenericScopedUnlock<CriticalSection> unlocker (myCriticalSection); 109 110 // myCriticalSection is now unlocked for the remainder of this block, 111 // and re-locked at the end. 112 113 ...do some stuff with it unlocked ... 114 } 115 116 // myCriticalSection gets unlocked here. 117 } 118 @endcode 119 120 @see GenericScopedLock, CriticalSection, ScopedLock, ScopedUnlock 121 122 @tags{Core} 123 */ 124 template <class LockType> 125 class GenericScopedUnlock 126 { 127 public: 128 //============================================================================== 129 /** Creates a GenericScopedUnlock. 130 131 As soon as it is created, this will unlock the CriticalSection, and 132 when the ScopedLock object is deleted, the CriticalSection will 133 be re-locked. 134 135 Make sure this object is created and deleted by the same thread, 136 otherwise there are no guarantees what will happen! Best just to use it 137 as a local stack object, rather than creating one with the new() operator. 138 */ GenericScopedUnlock(const LockType & lock)139 inline explicit GenericScopedUnlock (const LockType& lock) noexcept : lock_ (lock) { lock.exit(); } 140 141 /** Destructor. 142 143 The CriticalSection will be unlocked when the destructor is called. 144 145 Make sure this object is created and deleted by the same thread, 146 otherwise there are no guarantees what will happen! 147 */ ~GenericScopedUnlock()148 inline ~GenericScopedUnlock() noexcept { lock_.enter(); } 149 150 151 private: 152 //============================================================================== 153 const LockType& lock_; 154 155 JUCE_DECLARE_NON_COPYABLE (GenericScopedUnlock) 156 }; 157 158 159 //============================================================================== 160 /** 161 Automatically locks and unlocks a mutex object. 162 163 Use one of these as a local variable to provide RAII-based locking of a mutex. 164 165 The templated class could be a CriticalSection, SpinLock, or anything else that 166 provides enter() and exit() methods. 167 168 e.g. @code 169 170 CriticalSection myCriticalSection; 171 172 for (;;) 173 { 174 const GenericScopedTryLock<CriticalSection> myScopedTryLock (myCriticalSection); 175 176 // Unlike using a ScopedLock, this may fail to actually get the lock, so you 177 // should test this with the isLocked() method before doing your thread-unsafe 178 // action.. 179 if (myScopedTryLock.isLocked()) 180 { 181 ...do some stuff... 182 } 183 else 184 { 185 ..our attempt at locking failed because another thread had already locked it.. 186 } 187 188 // myCriticalSection gets unlocked here (if it was locked) 189 } 190 @endcode 191 192 @see CriticalSection::tryEnter, GenericScopedLock, GenericScopedUnlock 193 194 @tags{Core} 195 */ 196 template <class LockType> 197 class GenericScopedTryLock 198 { 199 public: 200 //============================================================================== 201 /** Creates a GenericScopedTryLock. 202 203 If acquireLockOnInitialisation is true then as soon as this ScopedTryLock 204 is created, it will attempt to acquire the lock with tryEnter. 205 206 You can retry acquiring the lock by calling retryLock. 207 208 When GenericScopedTryLock is deleted, the lock will be released (if the lock 209 was successfully acquired). 210 211 Make sure this object is created and deleted by the same thread, 212 otherwise there are no guarantees what will happen! Best just to use it 213 as a local stack object, rather than creating one with the new() operator. 214 215 @see retryLock, isLocked 216 */ 217 inline explicit GenericScopedTryLock (const LockType& lock, bool acquireLockOnInitialisation = true) noexcept lock_(lock)218 : lock_ (lock), lockWasSuccessful (acquireLockOnInitialisation && lock.tryEnter()) {} 219 220 /** Destructor. 221 222 The mutex will be unlocked (if it had been successfully locked) when the 223 destructor is called. 224 225 Make sure this object is created and deleted by the same thread, 226 otherwise there are no guarantees what will happen! 227 */ ~GenericScopedTryLock()228 inline ~GenericScopedTryLock() noexcept { if (lockWasSuccessful) lock_.exit(); } 229 230 /** Returns true if the mutex was successfully locked. */ isLocked()231 bool isLocked() const noexcept { return lockWasSuccessful; } 232 233 /** Retry gaining the lock by calling tryEnter on the underlying lock. */ retryLock()234 bool retryLock() const noexcept { lockWasSuccessful = lock_.tryEnter(); return lockWasSuccessful; } 235 236 private: 237 //============================================================================== 238 const LockType& lock_; 239 mutable bool lockWasSuccessful; 240 241 JUCE_DECLARE_NON_COPYABLE (GenericScopedTryLock) 242 }; 243 244 } // namespace juce 245