Menu

[r73]: / trunk / src / ReaderWriterLock.h  Maximize  Restore  History

Download this file

186 lines (163 with data), 7.0 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*********************************************************************
CReaderWriterLock: A simple and fast reader-writer lock class in C++
has characters of .NET ReaderWriterLock class
Copyright (C) 2006 Quynh Nguyen Huu
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
Email questions, comments or suggestions to quynhnguyenhuu@gmail.com
*********************************************************************/
/*********************************************************************
Introduction:
This implementation is inspired by System.Threading.ReaderWriterLock in
.NET framework. Following are some important statements I excerpted
(with some words modified) from .NET document.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemThreadingReaderWriterLockClassTopic.asp
"ReaderWriterLock is used to synchronize access to a resource.
At any given time, it allows either concurrent read access for
multiple threads, or write access for a single thread.
In a situation where a resource is changed infrequently, a
ReaderWriterLock provides better throughput than a simple
one-at-a-time lock, such as CriticalSection or Mutex.
This library works best where most accesses are reads, while
writes are infrequent and of short duration.
While a writer is waiting for active reader locks to be released,
threads requesting new reader locks will have to wait in the reader
queue. Their requests are not granted, even though they could share
concurrent access with existing reader-lock holders; this helps
protect writers against indefinite blockage by readers..."
*********************************************************************/
#pragma once
#include <windows.h>
#include <map>
#if (_WIN32_WINNT >= 0x0403)
//////////////////////////////////////////////////////////////////
// On multiprocessor systems, this value define number of times
// that a thread tries to spin before actually performing a wait
// operation (see InitializeCriticalSectionAndSpinCount API)
#ifndef READER_WRITER_SPIN_COUNT
#define READER_WRITER_SPIN_COUNT 400
#endif READER_WRITER_SPIN_COUNT
#endif _WIN32_WINNT
//////////////////////////////////////////////////////////////////
// CReaderWriterLockNonReentrance class
// NOTE: This class doesn't support reentrance & lock escalation.
// May be deadlock in one of following situations:
// 1) Call AcquireReaderLock twice (reentrance)
// --> Revise execution flow.
// 2) Call AcquireWriterLock twice (reentrance)
// --> Revise execution flow.
// 3) Call AcquireReaderLock then AcquireWriterLock (lock escalation)
// --> Use ReleaseReaderAndAcquireWriterLock method
// 4) Call AcquireWriterLock then AcquireReaderLock (lock deescalation)
// --> Use DowngradeFromWriterLock method
class CReaderWriterLockNonReentrance
{
public:
CReaderWriterLockNonReentrance() throw();
~CReaderWriterLockNonReentrance() throw();
void AcquireReaderLock() throw();
void ReleaseReaderLock() throw();
void AcquireWriterLock() throw();
void ReleaseWriterLock() throw();
BOOL TryAcquireReaderLock() throw();
BOOL TryAcquireWriterLock() throw();
// When a thread calls ReleaseReaderAndAcquireWriterLock the reader lock is released,
// and the thread goes to the end of the queue for the writer lock.
// Thus, other threads might write to the resource before the thread
// that requested the upgrade is granted the writer lock.
void ReleaseReaderAndAcquireWriterLock() throw();
void DowngradeFromWriterLock() throw();
protected:
// A critical section to guard all the other members
CRITICAL_SECTION m_cs;
// Auto-reset event, will be dynamically created/destroyed on demand
HANDLE m_hSafeToWriteEvent;
// Manual-reset event, will be dynamically created/destroyed on demand
HANDLE m_hSafeToReadEvent;
// Total number of writers on this object
INT m_iNumOfWriter;
// Total number of readers have already owned this object
INT m_iNumOfReaderEntered;
// Total number of readers are waiting to be owners of this object
INT m_iNumOfReaderWaiting;
// Internal/Real implementation
void _AcquireReaderLockAndLeaveCS() throw();
void _ReleaseReaderLockAndLeaveCS() throw();
void _AcquireWriterLockAndLeaveCS(BOOL blMustWait) throw();
void _ReleaseWriterLockAndLeaveCS(BOOL blDowngrade) throw();
};
//////////////////////////////////////////////////////////////////
// CReaderWriterLock class
// This class supports reentrance & lock escalation
class CReaderWriterLock : private CReaderWriterLockNonReentrance
{
public:
CReaderWriterLock();
~CReaderWriterLock();
// If current thread was already a reader
// it will be upgraded to be writer automatically.
// BE CAREFUL! Other threads might write to the resource
// before current thread is successfully upgraded.
void AcquireWriterLock() throw();
void ReleaseWriterLock() throw();
void AcquireReaderLock() throw();
void ReleaseReaderLock() throw();
BOOL TryAcquireReaderLock() throw();
BOOL TryAcquireWriterLock() throw();
// Regardless of how many times current thread acquired reader
// or writer locks, a call to this method will release all locks.
// After that, any call to ReleaseWriterLock or ReleaseReaderLock
// will raise exception in DEBUG mode.
void ReleaseAllLocks() throw();
void GetCurrentThreadStatus(DWORD* lpdwReaderLockCounter,
DWORD* lpdwWriterLockCounter) const throw();
protected:
typedef std::map<DWORD,DWORD> CMapThreadToState;
CMapThreadToState m_map;
};
//////////////////////////////////////////////////////////////////
// CAutoReadLockT & CAutoWriteLockT classes
// Couple of template helper classes which would let one acquire a lock
// in a body of code and not have to worry about explicitly releasing
// that lock if an exception is encountered in that piece of code or
// if there are multiple return points out of that piece.
template<typename T>
class CAutoReadLockT
{
public:
CAutoReadLockT(T& objLock) throw() : m_lock(objLock)
{
m_lock.AcquireReaderLock();
}
~CAutoReadLockT() throw()
{
m_lock.ReleaseReaderLock();
}
protected:
T& m_lock;
};
template<typename T>
class CAutoWriteLockT
{
public :
CAutoWriteLockT(T& objLock) throw() : m_lock(objLock)
{
m_lock.AcquireWriterLock();
}
~CAutoWriteLockT() throw()
{
m_lock.ReleaseWriterLock();
}
protected:
T& m_lock;
};
//////////////////////////////////////////////////////////////////
// Instances of above template helper classes
typedef CAutoReadLockT<CReaderWriterLock> CAutoReadLock;
typedef CAutoWriteLockT<CReaderWriterLock> CAutoWriteLock;
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.