1 /* 2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 /** 17 * @file rwlock.h 18 * 19 * @brief Provides interfaces of RWLock in c_utils. 20 */ 21 22 #ifndef UTILS_RWLOCK_H 23 #define UTILS_RWLOCK_H 24 25 #include <atomic> 26 #include <thread> 27 28 #include "nocopyable.h" 29 30 namespace OHOS { 31 namespace Utils { 32 33 /** 34 * @brief Implements the <b>RWLock</b> class to ensure that read and write 35 * operations are thread-safe. 36 * 37 * Under RWLock, write operations are mutually exclusive, 38 * and read and write operations are mutually exclusive. 39 * However, read operations are not mutually exclusive. 40 */ 41 class RWLock : NoCopyable { 42 public: 43 /** 44 * @brief Enumerates the lock states. 45 */ 46 enum LockStatus { 47 LOCK_STATUS_WRITE = -1, 48 LOCK_STATUS_FREE = 0, 49 }; 50 51 /** 52 * @brief Creates an <b>RWLock</b> object. 53 * 54 * @param writeFirst Indicates whether the <b>RWLock</b> object is write-first. 55 */ RWLock()56 RWLock() : RWLock(true) {} 57 explicit RWLock(bool writeFirst); 58 59 /** 60 * @brief Destroys this <b>RWLock</b> object. 61 */ ~RWLock()62 ~RWLock() override {} 63 64 /** 65 * @brief Obtains a read lock. 66 * 67 * If the thread has obtained a write lock, this function returns directly. 68 * In write-first mode, a read lock can be obtained only when the state 69 * is non-write-locked and no other threads are waiting to write data. 70 * In other modes, a read lock can be obtained when the state is 71 * non-write-locked. 72 */ 73 void LockRead(); 74 75 /** 76 * @brief Releases the read lock. 77 * 78 * If the write lock has been obtained before, 79 * LockRead() will return directly. 80 * This function will also return directly when called. 81 */ 82 void UnLockRead(); 83 84 /** 85 *@brief Obtains a write lock 86 * 87 * If the thread has obtained a write lock, this function returns directly 88 * to avoid acquiring a lock, because write locks are exclusive. 89 * The write lock can be obtained only when no other thread has obtained a read 90 * lock or a write lock; otherwise, the thread shall wait. 91 */ 92 void LockWrite(); 93 94 /** 95 * @brief Releases the write lock. 96 * 97 * If the thread has not obtained a write lock, this function returns directly. 98 */ 99 void UnLockWrite(); 100 101 private: 102 bool writeFirst_; // Whether the thread is write-first. The value true means that the thread is write-first. 103 std::thread::id writeThreadID_; // ID of the write thread. 104 105 // Resource lock counter. -1 indicates the write state, 0 indicates the free state, and a value greater than 0 106 // indicates the shared read state. 107 std::atomic_int lockCount_; 108 109 // Thread counter waiting for the write lock. 110 std::atomic_uint writeWaitCount_; 111 }; 112 113 /** 114 * @brief UniqueWriteGuard object controls the ownership of a lockable object 115 * within a scope, and is used only as acquisition 116 * and release of write locks. 117 * It is actually an encapsulation of the RWLock class, which can be locked 118 * at construction time and unlocked during destruction, 119 * providing a convenient RAII mechanism. 120 */ 121 template <typename RWLockable> 122 class UniqueWriteGuard : NoCopyable { 123 public: UniqueWriteGuard(RWLockable & rwLockable)124 explicit UniqueWriteGuard(RWLockable &rwLockable) 125 : rwLockable_(rwLockable) 126 { 127 rwLockable_.LockWrite(); 128 } 129 ~UniqueWriteGuard()130 ~UniqueWriteGuard() override 131 { 132 rwLockable_.UnLockWrite(); 133 } 134 135 private: 136 UniqueWriteGuard() = delete; 137 138 private: 139 RWLockable &rwLockable_; 140 }; 141 142 143 /** 144 * @brief UniqueWriteGuard object controls the ownership of a lockable object 145 * within a scope, and is used only as acquisition 146 * and release of read locks. 147 * It is actually an encapsulation of the RWLock class, which can be locked 148 * at construction time and unlocked during destruction, 149 * providing a convenient RAII mechanism. 150 */ 151 template <typename RWLockable> 152 class UniqueReadGuard : NoCopyable { 153 public: UniqueReadGuard(RWLockable & rwLockable)154 explicit UniqueReadGuard(RWLockable &rwLockable) 155 : rwLockable_(rwLockable) 156 { 157 rwLockable_.LockRead(); 158 } 159 ~UniqueReadGuard()160 ~UniqueReadGuard() override 161 { 162 rwLockable_.UnLockRead(); 163 } 164 165 private: 166 UniqueReadGuard() = delete; 167 168 private: 169 RWLockable &rwLockable_; 170 }; 171 172 } // namespace Utils 173 } // namespace OHOS 174 #endif 175 176