Logo ROOT   6.12/07
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_TRWSpinLock
14 #define ROOT_TRWSpinLock
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 namespace ROOT {
26 namespace 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 
38  using local_t = LocalCounts*;
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  // }
77  ++fWriteRecurse;
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 
88 struct RecurseCounts {
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 
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  // }
138  ++fWriteRecurse;
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 
152 template <typename MutexT = ROOT::TSpinMutex, typename RecurseCountsT = Internal::RecurseCounts>
154 private:
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 
172 public:
175 
176  ////////////////////////////////////////////////////////////////////////
177  /// Regular constructor.
178  TReentrantRWLock() : fReaders(0), fReaderReservation(0), fWriterReservation(0), fWriter(false) {}
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::thread::id fWriterThread
! Holder of the write lock
MutexT fMutex
! RWlock internal mutex
void SetIsWriter(local_t &local)
std::atomic< int > fReaderReservation
! A reader wants access
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
TReentrantRWLock()
Regular constructor.
std::unordered_map< std::thread::id, size_t > ReaderColl_t
TVirtualRWMutex::Hint_t Hint_t
void ResetReadCount(local_t &local, int newvalue)
Hint_t * DecrementReadCount(local_t &local)
Hint_t * DecrementReadCount(local_t &local)
ReaderColl_t fReadersCount
! Set of reader thread ids
std::atomic< int > fWriterReservation
! A writer wants access
Hint_t * IncrementReadCount(local_t &local)
std::condition_variable_any fCond
! RWlock internal condition variable
XFontStruct * id
Definition: TGX11.cxx:108
size_t fWriteRecurse
! Number of re-entry in the lock by the same thread.
Hint_t * IncrementReadCount(local_t &local)
Hint_t * DecrementReadCount(local_t &local, MutexT &)
size_t & GetLocalReadersCount(local_t &local)
bool IsNotCurrentWriter(local_t &local) const
RecurseCountsT fRecurseCounts
! Trackers for re-entry in the lock by the same thread.
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()
bool IsCurrentWriter(local_t &local) const
Hint_t * IncrementReadCount(local_t &local, MutexT &)
size_t & GetLocalReadersCount(local_t &local)
Earlier lock state as returned by GetState() that can be passed to Restore()
std::atomic< bool > fWriter
! Is there a writer?
void ResetReadCount(local_t &local, int newvalue)
Hint_t * IncrementReadCount(local_t &local, MutexT &mutex)
std::atomic< int > fReaders
! Number of readers
Hint_t * DecrementReadCount(local_t &local, MutexT &mutex)