Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TReentrantRWLock.hxx
Go to the documentation of this file.
1// @(#)root/thread:$Id$
2// Authors: Enric Tejedor CERN 12/09/2016
3// Philippe Canal FNAL 12/09/2016
4
5/*************************************************************************
6 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#ifndef ROOT_TReentrantRWLock
14#define ROOT_TReentrantRWLock
15
16#include "ThreadLocalStorage.h"
17#include "ROOT/TSpinMutex.hxx"
18#include "TVirtualRWMutex.h"
19
20#include <atomic>
21#include <condition_variable>
22#include <thread>
23#include <unordered_map>
24
25#ifdef R__HAS_TBB
26#include "tbb/enumerable_thread_specific.h"
27#endif
28
29namespace ROOT {
30namespace Internal {
32 using Hint_t = TVirtualRWMutex::Hint_t;
33
34 struct LocalCounts {
35 size_t fReadersCount = 0;
36 bool fIsWriter = false;
37 };
38 size_t fWriteRecurse = 0; ///<! Number of re-entry in the lock by the same thread.
39
41
43
45 TTHREAD_TLS_DECL(LocalCounts, gLocal);
46 return &gLocal;
47 }
48
50 ++(local->fReadersCount);
51 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
52 }
53
54 template <typename MutexT>
56 return IncrementReadCount(local);
57 }
58
60 --(local->fReadersCount);
61 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
62 }
63
64 template <typename MutexT>
66 return DecrementReadCount(local);
67 }
68
69 void ResetReadCount(local_t &local, int newvalue) {
70 local->fReadersCount = newvalue;
71 }
72
73 bool IsCurrentWriter(local_t &local) { return local->fIsWriter; }
74 bool IsNotCurrentWriter(local_t &local) { return !local->fIsWriter; }
75
76 void SetIsWriter(local_t &local)
77 {
78 // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
79 // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
80 // }
82 local->fIsWriter = true;
83 }
84
86
87 void ResetIsWriter(local_t &local) { local->fIsWriter = false; }
88
89 size_t &GetLocalReadersCount(local_t &local) { return local->fReadersCount; }
90};
91
93 using Hint_t = TVirtualRWMutex::Hint_t;
94 using ReaderColl_t = std::unordered_map<std::thread::id, size_t>;
95 size_t fWriteRecurse = 0; ///<! Number of re-entry in the lock by the same thread.
96
97 std::thread::id fWriterThread; ///<! Holder of the write lock
98 ReaderColl_t fReadersCount; ///<! Set of reader thread ids
99
100 using local_t = std::thread::id;
101
102 local_t GetLocal() const { return std::this_thread::get_id(); }
103
105 auto &count = fReadersCount[local];
106 ++(count);
107 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&count);
108 }
109
110 template <typename MutexT>
112 {
113 std::unique_lock<MutexT> lock(mutex);
114 return IncrementReadCount(local);
115 }
116
118 auto &count = fReadersCount[local];
119 --count;
120 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&count);
121 }
122
123 template <typename MutexT>
125 {
126 std::unique_lock<MutexT> lock(mutex);
127 return DecrementReadCount(local);
128 }
129
130 void ResetReadCount(local_t &local, int newvalue) {
131 fReadersCount[local] = newvalue;
132 }
133
134 bool IsCurrentWriter(local_t &local) const { return fWriterThread == local; }
135 bool IsNotCurrentWriter(local_t &local) const { return fWriterThread != local; }
136
137 void SetIsWriter(local_t &local)
138 {
139 // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
140 // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
141 // }
143 fWriterThread = local;
144 }
145
147
148 void ResetIsWriter(local_t & /* local */) { fWriterThread = std::thread::id(); }
149
150 size_t &GetLocalReadersCount(local_t &local) { return fReadersCount[local]; }
151
152
153};
154
155#ifdef R__HAS_TBB
156struct RecurseCountsTBB {
157 using Hint_t = TVirtualRWMutex::Hint_t;
158
159 struct LocalCounts {
160 size_t fReadersCount = 0;
161 bool fIsWriter = false;
162 };
163 tbb::enumerable_thread_specific<LocalCounts> fLocalCounts;
164 size_t fWriteRecurse = 0; ///<! Number of re-entry in the lock by the same thread.
165
166 using local_t = LocalCounts*;
167
168 local_t GetLocal(){
169 return &fLocalCounts.local();
170 }
171
172 Hint_t *IncrementReadCount(local_t &local) {
173 ++(local->fReadersCount);
174 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
175 }
176
177 template <typename MutexT>
178 Hint_t *IncrementReadCount(local_t &local, MutexT &) {
179 return IncrementReadCount(local);
180 }
181
182 Hint_t *DecrementReadCount(local_t &local) {
183 --(local->fReadersCount);
184 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
185 }
186
187 template <typename MutexT>
188 Hint_t *DecrementReadCount(local_t &local, MutexT &) {
189 return DecrementReadCount(local);
190 }
191
192 void ResetReadCount(local_t &local, int newvalue) {
193 local->fReadersCount = newvalue;
194 }
195
196 bool IsCurrentWriter(local_t &local) { return local->fIsWriter; }
197 bool IsNotCurrentWriter(local_t &local) { return !local->fIsWriter; }
198
199 void SetIsWriter(local_t &local)
200 {
201 // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
202 // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
203 // }
204 ++fWriteRecurse;
205 local->fIsWriter = true;
206 }
207
208 void DecrementWriteCount() { --fWriteRecurse; }
209
210 void ResetIsWriter(local_t &local) { local->fIsWriter = false; }
211
212 size_t &GetLocalReadersCount(local_t &local) { return local->fReadersCount; }
213};
214
215struct RecurseCountsTBBUnique {
216 using Hint_t = TVirtualRWMutex::Hint_t;
217
218 struct LocalCounts {
219 size_t fReadersCount = 0;
220 bool fIsWriter = false;
221 };
222 tbb::enumerable_thread_specific<LocalCounts, tbb::cache_aligned_allocator<LocalCounts>, tbb::ets_key_per_instance> fLocalCounts;
223 size_t fWriteRecurse = 0; ///<! Number of re-entry in the lock by the same thread.
224
225 using local_t = LocalCounts*;
226
227 local_t GetLocal(){
228 return &fLocalCounts.local();
229 }
230
231 Hint_t *IncrementReadCount(local_t &local) {
232 ++(local->fReadersCount);
233 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
234 }
235
236 template <typename MutexT>
237 Hint_t *IncrementReadCount(local_t &local, MutexT &) {
238 return IncrementReadCount(local);
239 }
240
241 Hint_t *DecrementReadCount(local_t &local) {
242 --(local->fReadersCount);
243 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
244 }
245
246 template <typename MutexT>
247 Hint_t *DecrementReadCount(local_t &local, MutexT &) {
248 return DecrementReadCount(local);
249 }
250
251 void ResetReadCount(local_t &local, int newvalue) {
252 local->fReadersCount = newvalue;
253 }
254
255 bool IsCurrentWriter(local_t &local) { return local->fIsWriter; }
256 bool IsNotCurrentWriter(local_t &local) { return !local->fIsWriter; }
257
258 void SetIsWriter(local_t &local)
259 {
260 // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
261 // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
262 // }
263 ++fWriteRecurse;
264 local->fIsWriter = true;
265 }
266
267 void DecrementWriteCount() { --fWriteRecurse; }
268
269 void ResetIsWriter(local_t &local) { local->fIsWriter = false; }
270
271 size_t &GetLocalReadersCount(local_t &local) { return local->fReadersCount; }
272};
273#endif
274
275} // Internal
276
277template <typename MutexT = ROOT::TSpinMutex, typename RecurseCountsT = Internal::RecurseCounts>
279private:
280
281 std::atomic<int> fReaders; ///<! Number of readers
282 std::atomic<int> fReaderReservation; ///<! A reader wants access
283 std::atomic<int> fWriterReservation; ///<! A writer wants access
284 std::atomic<bool> fWriter; ///<! Is there a writer?
285 MutexT fMutex; ///<! RWlock internal mutex
286 std::condition_variable_any fCond; ///<! RWlock internal condition variable
287
288 RecurseCountsT fRecurseCounts; ///<! Trackers for re-entry in the lock by the same thread.
289
290 // size_t fWriteRecurse; ///<! Number of re-entry in the lock by the same thread.
291
292 // std::thread::id fWriterThread; ///<! Holder of the write lock
293 // ReaderColl_t fReadersCount; ///<! Set of reader thread ids
294
295 void AssertReadCountLocIsFromCurrentThread(const size_t* presumedLocalReadersCount);
296
297public:
300
301 ////////////////////////////////////////////////////////////////////////
302 /// Regular constructor.
304
305 TVirtualRWMutex::Hint_t *ReadLock();
306 void ReadUnLock(TVirtualRWMutex::Hint_t *);
307 TVirtualRWMutex::Hint_t *WriteLock();
308 void WriteUnLock(TVirtualRWMutex::Hint_t *);
309
310 std::unique_ptr<State> GetStateBefore();
311 std::unique_ptr<StateDelta> Rewind(const State &earlierState);
312 void Apply(std::unique_ptr<StateDelta> &&delta);
313 };
314} // end of namespace ROOT
315
316#endif
std::condition_variable_any fCond
! RWlock internal condition variable
void WriteUnLock(TVirtualRWMutex::Hint_t *)
Release the lock in write mode.
TVirtualRWMutex::State State
std::atomic< int > fReaderReservation
! A reader wants access
std::unique_ptr< StateDelta > Rewind(const State &earlierState)
Rewind to an earlier mutex state, returning the delta.
TVirtualRWMutex::Hint_t * ReadLock()
Acquire the lock in read mode.
RecurseCountsT fRecurseCounts
! Trackers for re-entry in the lock by the same thread.
TVirtualRWMutex::Hint_t * WriteLock()
Acquire the lock in write mode.
std::atomic< bool > fWriter
! Is there a writer?
std::atomic< int > fReaders
! Number of readers
void ReadUnLock(TVirtualRWMutex::Hint_t *)
Release the lock in read mode.
void AssertReadCountLocIsFromCurrentThread(const size_t *presumedLocalReadersCount)
Assert that presumedLocalReadersCount really matches the local read count.
MutexT fMutex
! RWlock internal mutex
std::unique_ptr< State > GetStateBefore()
Get the lock state before the most recent write lock was taken.
TReentrantRWLock()
Regular constructor.
void Apply(std::unique_ptr< StateDelta > &&delta)
Re-apply a delta.
std::atomic< int > fWriterReservation
! A writer wants access
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Hint_t * DecrementReadCount(local_t &local)
size_t fWriteRecurse
! Number of re-entry in the lock by the same thread.
Hint_t * DecrementReadCount(local_t &local, MutexT &mutex)
bool IsNotCurrentWriter(local_t &local) const
std::unordered_map< std::thread::id, size_t > ReaderColl_t
bool IsCurrentWriter(local_t &local) const
std::thread::id fWriterThread
! Holder of the write lock
TVirtualRWMutex::Hint_t Hint_t
Hint_t * IncrementReadCount(local_t &local)
void ResetReadCount(local_t &local, int newvalue)
ReaderColl_t fReadersCount
! Set of reader thread ids
Hint_t * IncrementReadCount(local_t &local, MutexT &mutex)
size_t & GetLocalReadersCount(local_t &local)
Hint_t * DecrementReadCount(local_t &local)
Hint_t * IncrementReadCount(local_t &local, MutexT &)
void ResetReadCount(local_t &local, int newvalue)
Hint_t * IncrementReadCount(local_t &local)
Hint_t * DecrementReadCount(local_t &local, MutexT &)
size_t & GetLocalReadersCount(local_t &local)
size_t fWriteRecurse
! Number of re-entry in the lock by the same thread.
State as returned by GetStateDelta() that can be passed to Restore()
Earlier lock state as returned by GetState() that can be passed to Restore()