Logo ROOT   6.10/09
Reference Guide
TRWSpinLock.cxx
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 /** \class TRWSpinLock
14  \brief An implementation of a read-write lock with an internal spin lock.
15 
16 This class provides an implementation of a read-write lock that uses an
17 internal spin lock and a condition variable to synchronize readers and
18 writers when necessary.
19 
20 The implementation tries to make faster the scenario when readers come
21 and go but there is no writer. In that case, readers will not pay the
22 price of taking the internal spin lock.
23 
24 Moreover, this RW lock tries to be fair with writers, giving them the
25 possibility to claim the lock and wait for only the remaining readers,
26 thus preventing starvation.
27 */
28 
29 #include "ROOT/TRWSpinLock.hxx"
30 
31 using namespace ROOT;
32 
33 ////////////////////////////////////////////////////////////////////////////
34 /// Acquire the lock in read mode.
36 {
38  if (!fWriter) {
39  // There is no writer, go freely to the critical section
40  ++fReaders;
42  } else {
43  // A writer claimed the RW lock, we will need to wait on the
44  // internal lock
46 
47  std::unique_lock<ROOT::TSpinMutex> lock(fMutex);
48 
49  // Wait for writers, if any
50  fCond.wait(lock, [this]{ return !fWriter; });
51 
52  // This RW lock now belongs to the readers
53  ++fReaders;
54 
55  lock.unlock();
56  }
57 }
58 
59 //////////////////////////////////////////////////////////////////////////
60 /// Release the lock in read mode.
62 {
63  --fReaders;
64  if (fWriterReservation && fReaders == 0) {
65  // We still need to lock here to prevent interleaving with a writer
66  std::lock_guard<ROOT::TSpinMutex> lock(fMutex);
67 
68  // Make sure you wake up a writer, if any
69  // Note: spurrious wakeups are okay, fReaders
70  // will be checked again in WriteLock
71  fCond.notify_all();
72  }
73 }
74 
75 //////////////////////////////////////////////////////////////////////////
76 /// Acquire the lock in write mode.
78 {
80 
81  std::unique_lock<ROOT::TSpinMutex> lock(fMutex);
82 
83  // Wait for other writers, if any
84  fCond.wait(lock, [this]{ return !fWriter; });
85 
86  // Claim the lock for this writer
87  fWriter = true;
88 
89  // Wait until all reader reservations finish
90  while(fReaderReservation) {};
91 
92  // Wait for remaining readers
93  fCond.wait(lock, [this]{ return fReaders == 0; });
94 
96 
97  lock.unlock();
98 }
99 
100 //////////////////////////////////////////////////////////////////////////
101 /// Release the lock in write mode.
103 {
104  // We need to lock here to prevent interleaving with a reader
105  std::lock_guard<ROOT::TSpinMutex> lock(fMutex);
106 
107  fWriter = false;
108 
109  // Notify all potential readers/writers that are waiting
110  fCond.notify_all();
111 }
112 
void WriteUnLock()
Release the lock in write mode.
std::condition_variable_any fCond
! RWlock internal condition variable
Definition: TRWSpinLock.hxx:30
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
ROOT::TSpinMutex fMutex
! RWlock internal mutex
Definition: TRWSpinLock.hxx:29
std::atomic< int > fReaderReservation
! A reader wants access
Definition: TRWSpinLock.hxx:26
std::atomic< bool > fWriter
! Is there a writer?
Definition: TRWSpinLock.hxx:28
std::atomic< int > fReaders
! Number of readers
Definition: TRWSpinLock.hxx:25
void WriteLock()
Acquire the lock in write mode.
Definition: TRWSpinLock.cxx:77
void ReadLock()
Acquire the lock in read mode.
Definition: TRWSpinLock.cxx:35
std::atomic< int > fWriterReservation
! A writer wants access
Definition: TRWSpinLock.hxx:27
void ReadUnLock()
Release the lock in read mode.
Definition: TRWSpinLock.cxx:61