CommitDlg: Update empty file list message
[TortoiseGit.git] / src / Utils / ReaderWriterLock.h
blob40d0a2ad1be05a7cd666c6b98b5c179491b29884
1 /*********************************************************************
2 CReaderWriterLock: A simple and fast reader-writer lock class in C++
3 has characters of .NET ReaderWriterLock class
4 Copyright (C) 2006 Quynh Nguyen Huu
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 Email questions, comments or suggestions to quynhnguyenhuu@gmail.com
17 *********************************************************************/
19 /*********************************************************************
20 Introduction:
21 This implementation is inspired by System.Threading.ReaderWriterLock in
22 .NET framework. Following are some important statements I excerpted
23 (with some words modified) from .NET document.
25 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemThreadingReaderWriterLockClassTopic.asp
27 "ReaderWriterLock is used to synchronize access to a resource.
28 At any given time, it allows either concurrent read access for
29 multiple threads, or write access for a single thread.
30 In a situation where a resource is changed infrequently, a
31 ReaderWriterLock provides better throughput than a simple
32 one-at-a-time lock, such as CriticalSection or Mutex.
34 This library works best where most accesses are reads, while
35 writes are infrequent and of short duration.
37 While a writer is waiting for active reader locks to be released,
38 threads requesting new reader locks will have to wait in the reader
39 queue. Their requests are not granted, even though they could share
40 concurrent access with existing reader-lock holders; this helps
41 protect writers against indefinite blockage by readers..."
42 *********************************************************************/
44 #pragma once
46 #include <windows.h>
47 #include <map>
49 #if (_WIN32_WINNT >= 0x0403)
50 //////////////////////////////////////////////////////////////////
51 // On multiprocessor systems, this value define number of times
52 // that a thread tries to spin before actually performing a wait
53 // operation (see InitializeCriticalSectionAndSpinCount API)
54 #ifndef READER_WRITER_SPIN_COUNT
55 #define READER_WRITER_SPIN_COUNT 400
56 #endif READER_WRITER_SPIN_COUNT
57 #endif _WIN32_WINNT
59 // Forward reference
60 class CReaderWriterLock;
62 //////////////////////////////////////////////////////////////////
63 // CReaderWriterLockNonReentrance class
64 // NOTE: This class doesn't support reentrance & lock escalation.
65 // May be deadlock in one of following situations:
66 // 1) Call AcquireReaderLock twice (reentrance)
67 // --> Revise execution flow.
68 // 2) Call AcquireWriterLock twice (reentrance)
69 // --> Revise execution flow.
70 // 3) Call AcquireReaderLock then AcquireWriterLock (lock escalation)
71 // --> Use ReleaseReaderAndAcquireWriterLock method
72 // 4) Call AcquireWriterLock then AcquireReaderLock (lock deescalation)
73 // --> Use DowngradeFromWriterLock method
74 class CReaderWriterLockNonReentrance
76 public:
77 CReaderWriterLockNonReentrance() throw();
78 ~CReaderWriterLockNonReentrance() throw();
79 bool AcquireReaderLock(DWORD dwTimeout = INFINITE) throw();
80 void ReleaseReaderLock() throw();
81 bool AcquireWriterLock(DWORD dwTimeout = INFINITE) throw();
82 void ReleaseWriterLock() throw();
83 bool TryAcquireReaderLock() throw();
84 bool TryAcquireWriterLock() throw();
85 void DowngradeFromWriterLock() throw();
87 // When a thread calls UpgradeToWriterLock, the reader lock is released,
88 // and the thread goes to the end of the writer queue. Thus, other threads
89 // might write to resources before this method returns
90 bool UpgradeToWriterLock(DWORD dwTimeout = INFINITE) throw();
91 protected:
92 // A critical section to guard all the other members
93 mutable CRITICAL_SECTION m_cs;
94 // Auto-reset event, will be dynamically created/destroyed on demand
95 volatile HANDLE m_hSafeToWriteEvent;
96 // Manual-reset event, will be dynamically created/destroyed on demand
97 volatile HANDLE m_hSafeToReadEvent;
98 // Total number of writers on this object
99 volatile INT m_iNumOfWriter;
100 // Total number of readers have already owned this object
101 volatile INT m_iNumOfReaderEntered;
102 // Total number of readers are waiting to be owners of this object
103 volatile INT m_iNumOfReaderWaiting;
104 // Internal/Real implementation
105 void EnterCS() const throw();
106 void LeaveCS() const throw();
107 bool _ReaderWait(DWORD dwTimeout) throw();
108 bool _WriterWaitAndLeaveCSIfSuccess(DWORD dwTimeout) throw();
109 bool _UpgradeToWriterLockAndLeaveCS(DWORD dwTimeout) throw();
110 void _ReaderRelease() throw();
111 void _WriterRelease(bool blDowngrade) throw();
113 friend CReaderWriterLock;
116 //////////////////////////////////////////////////////////////////
117 // CReaderWriterLock class
118 // This class supports reentrance & lock escalation
119 class CReaderWriterLock
121 public:
122 CReaderWriterLock();
123 ~CReaderWriterLock();
125 bool AcquireReaderLock(DWORD dwTimeout = INFINITE) throw();
126 void ReleaseReaderLock() throw();
128 // If current thread was already a reader
129 // it will be upgraded to be writer automatically.
130 // BE CAREFUL! Other threads might write to the resource
131 // before current thread is successfully upgraded.
132 bool AcquireWriterLock(DWORD dwTimeout = INFINITE) throw();
133 void ReleaseWriterLock() throw();
135 // Regardless of how many times current thread acquired reader
136 // or writer locks, a call to this method will release all locks.
137 // After that, any call to ReleaseWriterLock or ReleaseReaderLock
138 // will raise exception in DEBUG mode.
139 void ReleaseAllLocks() throw();
141 // Query thread's status
142 DWORD GetCurrentThreadStatus() const throw();
143 void GetCurrentThreadStatus(DWORD* lpdwReaderLockCounter,
144 DWORD* lpdwWriterLockCounter) const throw();
145 protected:
146 CReaderWriterLockNonReentrance m_impl;
148 typedef std::map<DWORD,DWORD> CMapThreadToState;
149 CMapThreadToState m_map;
152 //////////////////////////////////////////////////////////////////
153 // CAutoReadLockT & CAutoWriteLockT classes
154 // Couple of template helper classes which would let one acquire a lock
155 // in a body of code and not have to worry about explicitly releasing
156 // that lock if an exception is encountered in that piece of code or
157 // if there are multiple return points out of that piece.
159 template<typename T>
160 class CAutoReadLockT
162 public:
163 CAutoReadLockT(T& objLock) throw() : m_lock(objLock)
165 m_lock.AcquireReaderLock();
167 ~CAutoReadLockT() throw()
169 m_lock.ReleaseReaderLock();
171 protected:
172 T& m_lock;
175 template<typename T>
176 class CAutoWriteLockT
178 public :
179 CAutoWriteLockT(T& objLock) throw() : m_lock(objLock)
181 m_lock.AcquireWriterLock();
183 ~CAutoWriteLockT() throw()
185 m_lock.ReleaseWriterLock();
187 protected:
188 T& m_lock;
191 template<typename T>
192 class CAutoReadWeakLockT
194 public:
195 CAutoReadWeakLockT(T& objLock, DWORD timeout = 1) throw() : m_lock(objLock)
197 isAcquired = m_lock.AcquireReaderLock(timeout);
199 ~CAutoReadWeakLockT() throw()
201 if (isAcquired)
202 m_lock.ReleaseReaderLock();
204 bool IsAcquired() const
206 return isAcquired;
208 protected:
209 T& m_lock;
210 bool isAcquired;
213 template<typename T>
214 class CAutoWriteWeakLockT
216 public :
217 CAutoWriteWeakLockT(T& objLock, DWORD timeout = 1) throw() : m_lock(objLock)
219 isAcquired = m_lock.AcquireWriterLock(timeout);
221 ~CAutoWriteWeakLockT() throw()
223 release();
225 void Release()
227 release();
229 bool IsAcquired() const
231 return isAcquired;
233 protected:
234 T& m_lock;
235 bool isAcquired;
237 void release()
239 if (isAcquired)
241 m_lock.ReleaseWriterLock();
242 isAcquired = false;
247 //////////////////////////////////////////////////////////////////
248 // Instances of above template helper classes
250 typedef CAutoReadLockT<CReaderWriterLock> CAutoReadLock;
251 typedef CAutoWriteLockT<CReaderWriterLock> CAutoWriteLock;
252 typedef CAutoReadWeakLockT<CReaderWriterLock> CAutoReadWeakLock;
253 typedef CAutoWriteWeakLockT<CReaderWriterLock> CAutoWriteWeakLock;
255 //////////////////////////////////////////////////////////////////
256 // Inline methods
258 __forceinline
259 void CReaderWriterLockNonReentrance::EnterCS() const throw() {
260 ::EnterCriticalSection(&m_cs);
263 __forceinline
264 void CReaderWriterLockNonReentrance::LeaveCS() const throw(){
265 ::LeaveCriticalSection(&m_cs);