Kea 2.7.5
readwrite_mutex.h
Go to the documentation of this file.
1// Copyright (C) 2020-2022 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#ifndef READWRITE_MUTEX_H
8#define READWRITE_MUTEX_H
9
15
17#include <boost/noncopyable.hpp>
18#include <climits>
19#include <condition_variable>
20#include <mutex>
21
22namespace isc {
23namespace util {
24
29class ReadWriteMutex : public boost::noncopyable {
30public:
31
33
35 static const unsigned WRITE_ENTERED =
36 1U << (sizeof(unsigned) * CHAR_BIT - 1);
37
39 static const unsigned MAX_READERS = ~WRITE_ENTERED;
40
42 ReadWriteMutex() : state_(0) {
43 }
44
49 virtual ~ReadWriteMutex() {
50 std::lock_guard<std::mutex> lk(mutex_);
51 }
52
54 void writeLock() {
55 std::unique_lock<std::mutex> lk(mutex_);
56 // Wait until the write entered flag can be set.
57 gate1_.wait(lk, [&]() { return (!writeEntered()); });
58 state_ |= WRITE_ENTERED;
59 // Wait until there are no more readers.
60 gate2_.wait(lk, [&]() { return (readers() == 0); });
61 }
62
66 void writeUnlock() {
67 std::lock_guard<std::mutex> lk(mutex_);
68 state_ = 0;
69 // Wake-up waiting threads when exiting the guard.
70 gate1_.notify_all();
71 }
72
74 void readLock() {
75 std::unique_lock<std::mutex> lk(mutex_);
76 // Wait if there is a writer or if readers overflow.
77 gate1_.wait(lk, [&]() { return (state_ < MAX_READERS); });
78 ++state_;
79 }
80
84 void readUnlock() {
85 std::lock_guard<std::mutex> lk(mutex_);
86 unsigned prev = state_--;
87 if (writeEntered()) {
88 if (readers() == 0) {
89 // Last reader: wake up a waiting writer.
90 gate2_.notify_one();
91 }
92 } else {
93 if (prev == MAX_READERS) {
94 // Reader overflow: wake up one waiting reader.
95 gate1_.notify_one();
96 }
97 }
98 }
99
100private:
101
103
105 bool writeEntered() const {
106 return (state_ & WRITE_ENTERED);
107 }
108
110 unsigned readers() const {
111 return (state_ & MAX_READERS);
112 }
113
115
119 std::mutex mutex_;
120
124 std::condition_variable gate1_;
125
129 std::condition_variable gate2_;
130
134 unsigned state_;
135};
136
140class ReadLockGuard : public boost::noncopyable {
141public:
142
146 ReadLockGuard(ReadWriteMutex& rw_mutex) : rw_mutex_(rw_mutex) {
147 rw_mutex_.readLock();
148 }
149
151 virtual ~ReadLockGuard() {
152 rw_mutex_.readUnlock();
153 }
154
155private:
157 ReadWriteMutex& rw_mutex_;
158
159};
160
164class WriteLockGuard : public boost::noncopyable {
165public:
166
170 WriteLockGuard(ReadWriteMutex& rw_mutex) : rw_mutex_(rw_mutex) {
171 rw_mutex_.writeLock();
172 }
173
175 virtual ~WriteLockGuard() {
176 rw_mutex_.writeUnlock();
177 }
178
179private:
181 ReadWriteMutex& rw_mutex_;
182};
183
184} // namespace util
185} // namespace isc
186
187#endif // READWRITE_MUTEX_H
Read mutex RAII handler.
virtual ~ReadLockGuard()
Destructor.
ReadLockGuard(ReadWriteMutex &rw_mutex)
Constructor.
void readUnlock()
Unlock read.
virtual ~ReadWriteMutex()
Destructor.
void writeLock()
Lock write.
static const unsigned WRITE_ENTERED
Constants.
static const unsigned MAX_READERS
The maximum number of readers (flag complement so 2^31 - 1).
void writeUnlock()
Unlock write.
Write mutex RAII handler.
WriteLockGuard(ReadWriteMutex &rw_mutex)
Constructor.
virtual ~WriteLockGuard()
Destructor.
Defines the logger used by the top-level component of kea-lfc.