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 30namespace OHOS { 31namespace 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 */ 41class RWLock : NoCopyable { 42public: 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 */ 56 RWLock() : RWLock(true) {} 57 explicit RWLock(bool writeFirst); 58 59/** 60 * @brief Destroys this <b>RWLock</b> object. 61 */ 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 101private: 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 */ 121template <typename RWLockable> 122class UniqueWriteGuard : NoCopyable { 123public: 124 explicit UniqueWriteGuard(RWLockable &rwLockable) 125 : rwLockable_(rwLockable) 126 { 127 rwLockable_.LockWrite(); 128 } 129 130 ~UniqueWriteGuard() override 131 { 132 rwLockable_.UnLockWrite(); 133 } 134 135private: 136 UniqueWriteGuard() = delete; 137 138private: 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 */ 151template <typename RWLockable> 152class UniqueReadGuard : NoCopyable { 153public: 154 explicit UniqueReadGuard(RWLockable &rwLockable) 155 : rwLockable_(rwLockable) 156 { 157 rwLockable_.LockRead(); 158 } 159 160 ~UniqueReadGuard() override 161 { 162 rwLockable_.UnLockRead(); 163 } 164 165private: 166 UniqueReadGuard() = delete; 167 168private: 169 RWLockable &rwLockable_; 170}; 171 172} // namespace Utils 173} // namespace OHOS 174#endif 175 176