BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmt_readerwritermutex.h
Go to the documentation of this file.
1/// @file bslmt_readerwritermutex.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_readerwritermutex.h -*-C++-*-
8
9#ifndef INCLUDED_BSLMT_READERWRITERMUTEX
10#define INCLUDED_BSLMT_READERWRITERMUTEX
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup bslmt_readerwritermutex bslmt_readerwritermutex
16/// @brief Provide a multi-reader/single-writer lock.
17/// @addtogroup bsl
18/// @{
19/// @addtogroup bslmt
20/// @{
21/// @addtogroup bslmt_readerwritermutex
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#bslmt_readerwritermutex-purpose"> Purpose</a>
26/// * <a href="#bslmt_readerwritermutex-classes"> Classes </a>
27/// * <a href="#bslmt_readerwritermutex-description"> Description </a>
28/// * <a href="#bslmt_readerwritermutex-bslmt-readwrite-locking-components"> bslmt ReadWrite Locking Components </a>
29/// * <a href="#bslmt_readerwritermutex-usage"> Usage </a>
30/// * <a href="#bslmt_readerwritermutex-example-1-maintaining-an-account-balance"> Example 1: Maintaining an Account Balance </a>
31///
32/// # Purpose {#bslmt_readerwritermutex-purpose}
33/// Provide a multi-reader/single-writer lock.
34///
35/// # Classes {#bslmt_readerwritermutex-classes}
36///
37/// - bslmt::ReaderWriterMutex: multi-reader/single-writer lock class
38///
39/// @see bslmt_readerwriterlock, bslmt_readlockguard,
40/// bslmt_writelockguard, bslmt_readerwriterlockassert
41///
42/// # Description {#bslmt_readerwritermutex-description}
43/// This component defines an efficient multi-reader/single-writer
44/// lock mechanism, `bslmt::ReaderWriterMutex`. It is designed to allow
45/// concurrent *read* access to a shared resource while still controlling
46/// *write* access.
47///
48/// Reader-writer locks are generally used for resources that are frequently
49/// read and less frequently updated. Unlike other lock mechanisms (e.g.,
50/// "mutexes"), reader-writer locks provide two distinct but mutually exclusive
51/// lock states: a *read* *lock* state, and a *write* *lock* state.
52///
53/// To the extent the implementation's underlying mutex prevents a thread from
54/// starving, readers can not be starved by writers and writers can not be
55/// starved by readers. If the underlying mutex, to some extent, favors
56/// re-acquisition of the mutex to allowing a new thread to obtain the mutex
57/// (e.g., the mutex obtained on Linux), this reader-writer lock is writer
58/// biased since writers can re-acquire the lock in the presence of readers but
59/// readers will not be able to re-acquire the lock in the presence of writers.
60///
61/// ## bslmt ReadWrite Locking Components {#bslmt_readerwritermutex-bslmt-readwrite-locking-components}
62///
63///
64/// * `bslmt::ReaderWriterMutex` (defined in this component). Preferred for
65/// most use-cases, has been shown to be faster than
66/// `bslmt::ReaderWriterLock` under most conditions and is generally the best
67/// choice.
68/// * `bslmt::ReaderWriterLock`: Preferred only when very long hold times are
69/// anticipated. It also provides `upgrade*` methods from a locked-for-read
70/// state to a locked-for-write state, but the use of this feature is
71/// discouraged as it has performed poorly on benchmarks.
72/// * `bslmt::RWMutex`: Deprecated.
73///
74/// Note that for extremely short hold times and very high concurrency, a
75/// `bslmt::Mutex` might outperform all of the above.
76///
77/// ## Usage {#bslmt_readerwritermutex-usage}
78///
79///
80/// This section illustrates intended use of this component.
81///
82/// ### Example 1: Maintaining an Account Balance {#bslmt_readerwritermutex-example-1-maintaining-an-account-balance}
83///
84///
85/// The following snippets of code illustrate the use of
86/// `bslmt::ReaderWriterMutex` to write a thread-safe class, `my_Account`. Note
87/// the typical use of `mutable` for the lock:
88/// @code
89/// // This `class` represents a bank account with a single balance.
90/// class my_Account {
91///
92/// // DATA
93/// bsls::Types::Uint64 d_pennies; // amount of money in the
94/// // account
95///
96/// mutable bslmt::ReaderWriterMutex d_lock; // guard access to
97/// // `d_account_p`
98///
99/// public:
100/// // CREATORS
101///
102/// /// Create an account with zero balance.
103/// my_Account();
104///
105/// /// Create an account having the value of the specified `original`
106/// /// account.
107/// my_Account(const my_Account& original);
108///
109/// /// Destroy this account.
110/// ~my_Account();
111///
112/// // MANIPULATORS
113///
114/// /// Atomically assign to this account the value of the specified
115/// /// `rhs` account, and return a reference to this modifiable
116/// /// account. Note that this operation is thread-safe; no `lock` is
117/// /// needed.
118/// my_Account& operator=(const my_Account& rhs);
119///
120/// /// Atomically deposit the specified `pennies` into this account.
121/// /// Note that this operation is thread-safe; no `lock` is needed.
122/// void deposit(bsls::Types::Uint64 pennies);
123///
124/// /// Attempt to atomically withdraw the specified `pennies` from this
125/// /// account. Return 0 on success and update this account to reflect
126/// /// the withdrawal. Otherwise, return a non-zero value and do not
127/// /// update the balance of this account. Note that this operation is
128/// /// thread-safe; no `lock` is needed.
129/// int withdraw(bsls::Types::Uint64 pennies);
130///
131/// // ACCESSORS
132///
133/// /// Atomically return the number of pennies that are available for
134/// /// withdrawal from this account.
135/// bsls::Types::Uint64 balanceInPennies() const;
136/// };
137///
138/// // CREATORS
139/// my_Account::my_Account()
140/// : d_pennies(0)
141/// {
142/// }
143///
144/// my_Account::my_Account(const my_Account& original)
145/// : d_pennies(original.balanceInPennies())
146/// {
147/// }
148///
149/// my_Account::~my_Account()
150/// {
151/// }
152///
153/// // MANIPULATORS
154/// my_Account& my_Account::operator=(const my_Account& rhs)
155/// {
156/// @endcode
157/// Where appropriate, clients should use a lock-guard to ensure that an
158/// acquired mutex is always properly released, even if an exception is thrown.
159/// @code
160/// d_lock.lockWrite();
161/// d_pennies = rhs.balanceInPennies();
162/// d_lock.unlockWrite();
163/// return *this;
164/// }
165///
166/// void my_Account::deposit(bsls::Types::Uint64 pennies)
167/// {
168/// d_lock.lockWrite();
169/// d_pennies += pennies;
170/// d_lock.unlockWrite();
171/// }
172///
173/// int my_Account::withdraw(bsls::Types::Uint64 pennies)
174/// {
175/// int rv = 0;
176///
177/// d_lock.lockWrite();
178///
179/// if (pennies <= d_pennies) {
180/// d_pennies -= pennies;
181/// }
182/// else {
183/// rv = 1;
184/// }
185///
186/// d_lock.unlockWrite();
187///
188/// return rv;
189/// }
190///
191/// // ACCESSORS
192/// bsls::Types::Uint64 my_Account::balanceInPennies() const
193/// {
194/// d_lock.lockRead();
195/// bsls::Types::Uint64 rv = d_pennies;
196/// d_lock.unlockRead();
197/// return rv;
198/// }
199/// @endcode
200/// The atomic `my_Account` methods are used as expected:
201/// @code
202/// my_Account account;
203///
204/// account.deposit(10050);
205/// assert(10050 == account.balanceInPennies());
206///
207/// bsls::Types::Uint64 paycheckInPennies = 5025;
208///
209/// account.deposit(paycheckInPennies);
210/// assert(15075 == account.balanceInPennies());
211/// @endcode
212/// @}
213/** @} */
214/** @} */
215
216/** @addtogroup bsl
217 * @{
218 */
219/** @addtogroup bslmt
220 * @{
221 */
222/** @addtogroup bslmt_readerwritermutex
223 * @{
224 */
225
226#include <bslscm_version.h>
227
228#include <bslmt_mutex.h>
230#include <bslmt_semaphore.h>
231
233
234
235namespace bslmt {
236
237 // =======================
238 // class ReaderWriterMutex
239 // =======================
240
241/// This class provides a multi-reader/single-writer lock mechanism.
242///
243/// See @ref bslmt_readerwritermutex
245
246 // DATA
248
249 private:
250 // NOT IMPLEMENTED
252 ReaderWriterMutex& operator=(const ReaderWriterMutex&);
253
254 public:
255 // CREATORS
256
257 /// Construct a reader/writer lock initialized to an unlocked state.
259
260 /// Destroy this object
262
263 // MANIPULATORS
264
265 /// Lock this reader-writer mutex for reading. If there are no active
266 /// or pending write locks, lock this mutex for reading and return
267 /// immediately. Otherwise, block until the read lock on this mutex is
268 /// acquired. Use `unlockRead` or `unlock` to release the lock on this
269 /// mutex. The behavior is undefined if this method is called from a
270 /// thread that already has a lock on this mutex.
271 void lockRead();
272
273 /// Lock this reader-writer mutex for writing. If there are no active
274 /// or pending locks on this mutex, lock this mutex for writing and
275 /// return immediately. Otherwise, block until the write lock on this
276 /// mutex is acquired. Use `unlockWrite` or `unlock` to release the
277 /// lock on this mutex. The behavior is undefined if this method is
278 /// called from a thread that already has a lock on this mutex.
279 void lockWrite();
280
281 /// Attempt to lock this reader-writer mutex for reading. Immediately
282 /// return 0 on success, and a non-zero value if there are active or
283 /// pending writers. If successful, `unlockRead` or `unlock` must be
284 /// used to release the lock on this mutex. The behavior is undefined
285 /// if this method is called from a thread that already has a lock on
286 /// this mutex.
287 int tryLockRead();
288
289 /// Attempt to lock this reader-writer mutex for writing. Immediately
290 /// return 0 on success, and a non-zero value if there are active or
291 /// pending locks on this mutex. If successful, `unlockWrite` or
292 /// `unlock` must be used to release the lock on this mutex. The
293 /// behavior is undefined if this method is called from a thread that
294 /// already has a lock on this mutex.
295 int tryLockWrite();
296
297 /// Release the lock that the calling thread holds on this reader-writer
298 /// mutex. The behavior is undefined unless the calling thread
299 /// currently has a lock on this mutex.
300 void unlock();
301
302 /// Release the read lock that the calling thread holds on this
303 /// reader-writer mutex. The behavior is undefined unless the calling
304 /// thread currently has a read lock on this mutex.
305 void unlockRead();
306
307 /// Release the write lock that the calling thread holds on this
308 /// reader-writer mutex. The behavior is undefined unless the calling
309 /// thread currently has a write lock on this mutex.
310 void unlockWrite();
311
312 // ACCESSORS
313
314 /// Return `true` if this reader-write mutex is currently read locked or
315 /// write locked, and `false` otherwise.
316 bool isLocked() const;
317
318 /// Return `true` if this reader-write mutex is currently read locked,
319 /// and `false` otherwise.
320 bool isLockedRead() const;
321
322 /// Return `true` if this reader-write mutex is currently write locked,
323 /// and `false` otherwise.
324 bool isLockedWrite() const;
325};
326
327// ============================================================================
328// INLINE DEFINITIONS
329// ============================================================================
330
331 // -----------------------
332 // class ReaderWriterMutex
333 // -----------------------
334
335// CREATORS
336inline
340
341// MANIPULATORS
342inline
344{
345 d_impl.lockRead();
346}
347
348inline
350{
351 d_impl.lockWrite();
352}
353
354inline
356{
357 return d_impl.tryLockRead();
358}
359
360inline
362{
363 return d_impl.tryLockWrite();
364}
365
366inline
368{
369 d_impl.unlock();
370}
371
372inline
374{
375 d_impl.unlockRead();
376}
377
378inline
380{
381 d_impl.unlockWrite();
382}
383
384// ACCESSORS
385inline
387{
388 return d_impl.isLocked();
389}
390
391inline
393{
394 return d_impl.isLockedRead();
395}
396
397inline
399{
400 return d_impl.isLockedWrite();
401}
402
403} // close package namespace
404
405
406#endif
407
408// ----------------------------------------------------------------------------
409// Copyright 2016 Bloomberg Finance L.P.
410//
411// Licensed under the Apache License, Version 2.0 (the "License");
412// you may not use this file except in compliance with the License.
413// You may obtain a copy of the License at
414//
415// http://www.apache.org/licenses/LICENSE-2.0
416//
417// Unless required by applicable law or agreed to in writing, software
418// distributed under the License is distributed on an "AS IS" BASIS,
419// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
420// See the License for the specific language governing permissions and
421// limitations under the License.
422// ----------------------------- END-OF-FILE ----------------------------------
423
424/** @} */
425/** @} */
426/** @} */
Definition bslmt_readerwritermuteximpl.h:94
Definition bslmt_readerwritermutex.h:244
int tryLockWrite()
Definition bslmt_readerwritermutex.h:361
void unlockRead()
Definition bslmt_readerwritermutex.h:373
bool isLockedWrite() const
Definition bslmt_readerwritermutex.h:398
void unlock()
Definition bslmt_readerwritermutex.h:367
ReaderWriterMutex()
Construct a reader/writer lock initialized to an unlocked state.
Definition bslmt_readerwritermutex.h:337
void unlockWrite()
Definition bslmt_readerwritermutex.h:379
~ReaderWriterMutex()
Destroy this object.
int tryLockRead()
Definition bslmt_readerwritermutex.h:355
void lockRead()
Definition bslmt_readerwritermutex.h:343
bool isLockedRead() const
Definition bslmt_readerwritermutex.h:392
void lockWrite()
Definition bslmt_readerwritermutex.h:349
bool isLocked() const
Definition bslmt_readerwritermutex.h:386
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bslmt_barrier.h:344