Logo ROOT  
Reference Guide
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>
55 Hint_t *IncrementReadCount(local_t &local, 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>
65 Hint_t *DecrementReadCount(local_t &local, 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
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>
111 Hint_t *IncrementReadCount(local_t &local, MutexT &mutex)
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>
124 Hint_t *DecrementReadCount(local_t &local, MutexT &mutex)
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
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() { return &fLocalCounts.local(); }
169
170 Hint_t *IncrementReadCount(local_t &local)
171 {
172 ++(local->fReadersCount);
173 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
174 }
175
176 template <typename MutexT>
177 Hint_t *IncrementReadCount(local_t &local, MutexT &)
178 {
179 return IncrementReadCount(local);
180 }
181
182 Hint_t *DecrementReadCount(local_t &local)
183 {
184 --(local->fReadersCount);
185 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
186 }
187
188 template <typename MutexT>
189 Hint_t *DecrementReadCount(local_t &local, MutexT &)
190 {
191 return DecrementReadCount(local);
192 }
193
194 void ResetReadCount(local_t &local, int newvalue) { local->fReadersCount = newvalue; }
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>
223 fLocalCounts;
224 size_t fWriteRecurse = 0; ///<! Number of re-entry in the lock by the same thread.
225
226 using local_t = LocalCounts *;
227
228 local_t GetLocal() { return &fLocalCounts.local(); }
229
230 Hint_t *IncrementReadCount(local_t &local)
231 {
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 {
239 return IncrementReadCount(local);
240 }
241
242 Hint_t *DecrementReadCount(local_t &local)
243 {
244 --(local->fReadersCount);
245 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
246 }
247
248 template <typename MutexT>
249 Hint_t *DecrementReadCount(local_t &local, MutexT &)
250 {
251 return DecrementReadCount(local);
252 }
253
254 void ResetReadCount(local_t &local, int newvalue) { local->fReadersCount = newvalue; }
255
256 bool IsCurrentWriter(local_t &local) { return local->fIsWriter; }
257 bool IsNotCurrentWriter(local_t &local) { return !local->fIsWriter; }
258
259 void SetIsWriter(local_t &local)
260 {
261 // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
262 // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
263 // }
264 ++fWriteRecurse;
265 local->fIsWriter = true;
266 }
267
268 void DecrementWriteCount() { --fWriteRecurse; }
269
270 void ResetIsWriter(local_t &local) { local->fIsWriter = false; }
271
272 size_t &GetLocalReadersCount(local_t &local) { return local->fReadersCount; }
273};
274#endif
275
276} // Internal
277
278template <typename MutexT = ROOT::TSpinMutex, typename RecurseCountsT = Internal::RecurseCounts>
280private:
281
282 std::atomic<int> fReaders; ///<! Number of readers
283 std::atomic<int> fReaderReservation; ///<! A reader wants access
284 std::atomic<int> fWriterReservation; ///<! A writer wants access
285 std::atomic<bool> fWriter; ///<! Is there a writer?
286 MutexT fMutex; ///<! RWlock internal mutex
287 std::condition_variable_any fCond; ///<! RWlock internal condition variable
288
289 RecurseCountsT fRecurseCounts; ///<! Trackers for re-entry in the lock by the same thread.
290
291 // size_t fWriteRecurse; ///<! Number of re-entry in the lock by the same thread.
292
293 // std::thread::id fWriterThread; ///<! Holder of the write lock
294 // ReaderColl_t fReadersCount; ///<! Set of reader thread ids
295
296 void AssertReadCountLocIsFromCurrentThread(const size_t* presumedLocalReadersCount);
297
298public:
301
302 ////////////////////////////////////////////////////////////////////////
303 /// Regular constructor.
305
306 TVirtualRWMutex::Hint_t *ReadLock();
307 void ReadUnLock(TVirtualRWMutex::Hint_t *);
308 TVirtualRWMutex::Hint_t *WriteLock();
309 void WriteUnLock(TVirtualRWMutex::Hint_t *);
310
311 std::unique_ptr<State> GetStateBefore();
312 std::unique_ptr<StateDelta> Rewind(const State &earlierState);
313 void Apply(std::unique_ptr<StateDelta> &&delta);
314 };
315} // end of namespace ROOT
316
317#endif
XFontStruct * id
Definition: TGX11.cxx:109
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)
void SetIsWriter(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()