Logo ROOT   6.16/01
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
25namespace ROOT {
26namespace Internal {
28 using Hint_t = TVirtualRWMutex::Hint_t;
29
30 struct LocalCounts {
31 size_t fReadersCount = 0;
32 bool fIsWriter = false;
33 };
34 size_t fWriteRecurse = 0; ///<! Number of re-entry in the lock by the same thread.
35
37
39
41 TTHREAD_TLS_DECL(LocalCounts, gLocal);
42 return &gLocal;
43 }
44
46 ++(local->fReadersCount);
47 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
48 }
49
50 template <typename MutexT>
51 Hint_t *IncrementReadCount(local_t &local, MutexT &) {
52 return IncrementReadCount(local);
53 }
54
56 --(local->fReadersCount);
57 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&(local->fReadersCount));
58 }
59
60 template <typename MutexT>
61 Hint_t *DecrementReadCount(local_t &local, MutexT &) {
62 return DecrementReadCount(local);
63 }
64
65 void ResetReadCount(local_t &local, int newvalue) {
66 local->fReadersCount = newvalue;
67 }
68
69 bool IsCurrentWriter(local_t &local) { return local->fIsWriter; }
70 bool IsNotCurrentWriter(local_t &local) { return !local->fIsWriter; }
71
72 void SetIsWriter(local_t &local)
73 {
74 // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
75 // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
76 // }
78 local->fIsWriter = true;
79 }
80
82
83 void ResetIsWriter(local_t &local) { local->fIsWriter = false; }
84
85 size_t &GetLocalReadersCount(local_t &local) { return local->fReadersCount; }
86};
87
89 using Hint_t = TVirtualRWMutex::Hint_t;
90 using ReaderColl_t = std::unordered_map<std::thread::id, size_t>;
91 size_t fWriteRecurse; ///<! Number of re-entry in the lock by the same thread.
92
93 std::thread::id fWriterThread; ///<! Holder of the write lock
94 ReaderColl_t fReadersCount; ///<! Set of reader thread ids
95
96 using local_t = std::thread::id;
97
98 local_t GetLocal() const { return std::this_thread::get_id(); }
99
101 auto &count = fReadersCount[local];
102 ++(count);
103 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&count);
104 }
105
106 template <typename MutexT>
107 Hint_t *IncrementReadCount(local_t &local, MutexT &mutex)
108 {
109 std::unique_lock<MutexT> lock(mutex);
110 return IncrementReadCount(local);
111 }
112
114 auto &count = fReadersCount[local];
115 --count;
116 return reinterpret_cast<TVirtualRWMutex::Hint_t *>(&count);
117 }
118
119 template <typename MutexT>
120 Hint_t *DecrementReadCount(local_t &local, MutexT &mutex)
121 {
122 std::unique_lock<MutexT> lock(mutex);
123 return DecrementReadCount(local);
124 }
125
126 void ResetReadCount(local_t &local, int newvalue) {
127 fReadersCount[local] = newvalue;
128 }
129
130 bool IsCurrentWriter(local_t &local) const { return fWriterThread == local; }
131 bool IsNotCurrentWriter(local_t &local) const { return fWriterThread != local; }
132
133 void SetIsWriter(local_t &local)
134 {
135 // if (fWriteRecurse == std::numeric_limits<decltype(fWriteRecurse)>::max()) {
136 // ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
137 // }
139 fWriterThread = local;
140 }
141
143
144 void ResetIsWriter(local_t & /* local */) { fWriterThread = std::thread::id(); }
145
146 size_t &GetLocalReadersCount(local_t &local) { return fReadersCount[local]; }
147
148
149};
150} // Internal
151
152template <typename MutexT = ROOT::TSpinMutex, typename RecurseCountsT = Internal::RecurseCounts>
154private:
155
156 std::atomic<int> fReaders; ///<! Number of readers
157 std::atomic<int> fReaderReservation; ///<! A reader wants access
158 std::atomic<int> fWriterReservation; ///<! A writer wants access
159 std::atomic<bool> fWriter; ///<! Is there a writer?
160 MutexT fMutex; ///<! RWlock internal mutex
161 std::condition_variable_any fCond; ///<! RWlock internal condition variable
162
163 RecurseCountsT fRecurseCounts; ///<! Trackers for re-entry in the lock by the same thread.
164
165 // size_t fWriteRecurse; ///<! Number of re-entry in the lock by the same thread.
166
167 // std::thread::id fWriterThread; ///<! Holder of the write lock
168 // ReaderColl_t fReadersCount; ///<! Set of reader thread ids
169
170 void AssertReadCountLocIsFromCurrentThread(const size_t* presumedLocalReadersCount);
171
172public:
175
176 ////////////////////////////////////////////////////////////////////////
177 /// Regular constructor.
179
180 TVirtualRWMutex::Hint_t *ReadLock();
181 void ReadUnLock(TVirtualRWMutex::Hint_t *);
182 TVirtualRWMutex::Hint_t *WriteLock();
183 void WriteUnLock(TVirtualRWMutex::Hint_t *);
184
185 std::unique_ptr<State> GetStateBefore();
186 std::unique_ptr<StateDelta> Rewind(const State &earlierState);
187 void Apply(std::unique_ptr<StateDelta> &&delta);
188 };
189} // end of namespace ROOT
190
191#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
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
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()