Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmcppdap/src/rwmutex.h
3153 views
1
// Copyright 2020 Google LLC
2
//
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
// https://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
#ifndef dap_rwmutex_h
16
#define dap_rwmutex_h
17
18
#include <condition_variable>
19
#include <mutex>
20
21
namespace dap {
22
23
////////////////////////////////////////////////////////////////////////////////
24
// RWMutex
25
////////////////////////////////////////////////////////////////////////////////
26
27
// A RWMutex is a reader/writer mutual exclusion lock.
28
// The lock can be held by an arbitrary number of readers or a single writer.
29
// Also known as a shared mutex.
30
class RWMutex {
31
public:
32
inline RWMutex() = default;
33
34
// lockReader() locks the mutex for reading.
35
// Multiple read locks can be held while there are no writer locks.
36
inline void lockReader();
37
38
// unlockReader() unlocks the mutex for reading.
39
inline void unlockReader();
40
41
// lockWriter() locks the mutex for writing.
42
// If the lock is already locked for reading or writing, lockWriter blocks
43
// until the lock is available.
44
inline void lockWriter();
45
46
// unlockWriter() unlocks the mutex for writing.
47
inline void unlockWriter();
48
49
private:
50
RWMutex(const RWMutex&) = delete;
51
RWMutex& operator=(const RWMutex&) = delete;
52
53
int readLocks = 0;
54
int pendingWriteLocks = 0;
55
std::mutex mutex;
56
std::condition_variable cv;
57
};
58
59
void RWMutex::lockReader() {
60
std::unique_lock<std::mutex> lock(mutex);
61
readLocks++;
62
}
63
64
void RWMutex::unlockReader() {
65
std::unique_lock<std::mutex> lock(mutex);
66
readLocks--;
67
if (readLocks == 0 && pendingWriteLocks > 0) {
68
cv.notify_one();
69
}
70
}
71
72
void RWMutex::lockWriter() {
73
std::unique_lock<std::mutex> lock(mutex);
74
if (readLocks > 0) {
75
pendingWriteLocks++;
76
cv.wait(lock, [&] { return readLocks == 0; });
77
pendingWriteLocks--;
78
}
79
lock.release(); // Keep lock held
80
}
81
82
void RWMutex::unlockWriter() {
83
if (pendingWriteLocks > 0) {
84
cv.notify_one();
85
}
86
mutex.unlock();
87
}
88
89
////////////////////////////////////////////////////////////////////////////////
90
// RLock
91
////////////////////////////////////////////////////////////////////////////////
92
93
// RLock is a RAII read lock helper for a RWMutex.
94
class RLock {
95
public:
96
inline RLock(RWMutex& mutex);
97
inline ~RLock();
98
99
inline RLock(RLock&&);
100
inline RLock& operator=(RLock&&);
101
102
private:
103
RLock(const RLock&) = delete;
104
RLock& operator=(const RLock&) = delete;
105
106
RWMutex* m;
107
};
108
109
RLock::RLock(RWMutex& mutex) : m(&mutex) {
110
m->lockReader();
111
}
112
113
RLock::~RLock() {
114
if (m != nullptr) {
115
m->unlockReader();
116
}
117
}
118
119
RLock::RLock(RLock&& other) {
120
m = other.m;
121
other.m = nullptr;
122
}
123
124
RLock& RLock::operator=(RLock&& other) {
125
m = other.m;
126
other.m = nullptr;
127
return *this;
128
}
129
130
////////////////////////////////////////////////////////////////////////////////
131
// WLock
132
////////////////////////////////////////////////////////////////////////////////
133
134
// WLock is a RAII write lock helper for a RWMutex.
135
class WLock {
136
public:
137
inline WLock(RWMutex& mutex);
138
inline ~WLock();
139
140
inline WLock(WLock&&);
141
inline WLock& operator=(WLock&&);
142
143
private:
144
WLock(const WLock&) = delete;
145
WLock& operator=(const WLock&) = delete;
146
147
RWMutex* m;
148
};
149
150
WLock::WLock(RWMutex& mutex) : m(&mutex) {
151
m->lockWriter();
152
}
153
154
WLock::~WLock() {
155
if (m != nullptr) {
156
m->unlockWriter();
157
}
158
}
159
160
WLock::WLock(WLock&& other) {
161
m = other.m;
162
other.m = nullptr;
163
}
164
165
WLock& WLock::operator=(WLock&& other) {
166
m = other.m;
167
other.m = nullptr;
168
return *this;
169
}
170
} // namespace dap
171
172
#endif
173
174