xref: /commonlibrary/c_utils/base/include/rwlock.h (revision 3f4cbf05)
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