BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslmt_writelockguard.h
Go to the documentation of this file.
1/// @file bslmt_writelockguard.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmt_writelockguard.h -*-C++-*-
8#ifndef INCLUDED_BSLMT_WRITELOCKGUARD
9#define INCLUDED_BSLMT_WRITELOCKGUARD
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmt_writelockguard bslmt_writelockguard
15/// @brief Provide generic scoped guards for write synchronization objects.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmt
19/// @{
20/// @addtogroup bslmt_writelockguard
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmt_writelockguard-purpose"> Purpose</a>
25/// * <a href="#bslmt_writelockguard-classes"> Classes </a>
26/// * <a href="#bslmt_writelockguard-description"> Description </a>
27/// * <a href="#bslmt_writelockguard-behavior-of-the-release-method"> Behavior of the release Method </a>
28/// * <a href="#bslmt_writelockguard-usage"> Usage </a>
29/// * <a href="#bslmt_writelockguard-example-1-basic-usage"> Example 1: Basic Usage </a>
30///
31/// # Purpose {#bslmt_writelockguard-purpose}
32/// Provide generic scoped guards for write synchronization objects.
33///
34/// # Classes {#bslmt_writelockguard-classes}
35///
36/// - bslmt::WriteLockGuard: automatic locking-unlocking for write access
37/// - bslmt::WriteLockGuardUnlock: automatic unlocking-locking for write access
38/// - bslmt::WriteLockGuardTryLock: automatic non-blocking locking-unlocking
39/// - bslmt::LockWriteGuard: DEPRECATED
40///
41/// @see bslmt_lockguard, bslmt_readlockguard
42///
43/// # Description {#bslmt_writelockguard-description}
44/// This component provides generic guards,
45/// `bslmt::WriteLockGuard`, `bslmt::WriteLockGuardUnlock`, and
46/// `bslmt::WriteLockGuardTryLock`, to automatically lock and unlock an external
47/// synchronization object for writing. The synchronization object can be any
48/// type (e.g., `bslmt::ReaderWriterLock`) that provides the following methods:
49/// @code
50/// void lockWrite();
51/// void unlock();
52/// @endcode
53/// Both `bslmt::WriteLockGuard` and `bslmt::WriteLockGuardUnlock` implement the
54/// "construction is acquisition, destruction is release" idiom. During
55/// construction, `bslmt::WriteLockGuard` automatically calls `lockWrite` on the
56/// user-supplied object, and `unlock` when it is destroyed (unless released).
57/// `bslmt::WriteLockGuardUnlock` does the opposite -- it invokes the `unlock`
58/// method when constructed and the `lockWrite` method when destroyed.
59///
60/// A third type of guard, `bslmt::WriteLockGuardTryLock`, attempts to acquire a
61/// lock, and if acquisition succeeds, releases it upon destruction. Since the
62/// acquisition is done at construction time, it is not possible to return a
63/// value to indicate success. Rather, the `bslmt::WriteLockGuardTryLock`
64/// contains a pointer to the synchronization object if `tryLock` succeeds, and
65/// is null otherwise. The synchronization object can be any type (e.g.,
66/// `bslmt::Mutex` or `bslmt::RecursiveMutex`) that provides the following
67/// methods:
68/// @code
69/// int tryLockWrite();
70/// void unlock();
71/// @endcode
72/// Note that objects of neither guard type assumes ownership of the
73/// synchronization object passed at construction. Also note that objects of
74/// all of the guard types may be constructed with a null `lock` whereby the
75/// constructed guard objects guard no lock. The destructor of each of the
76/// guard types has no effect if no lock is under management.
77///
78/// ## Behavior of the release Method {#bslmt_writelockguard-behavior-of-the-release-method}
79///
80///
81/// Like all BDE guard classes, each of the three `bslmt::WriteLockGuard*`
82/// classes provides a `release` method that terminates the guard's management
83/// of any lock object that the guard holds. The `release` method has *no*
84/// *effect* on the state of the lock object.
85///
86/// In particular, `bslmt::WriteLockGuard::release` does not unlock the lock
87/// object under management. If a user wants to release the lock object *and*
88/// unlock the lock object (because the lock is no longer required before the
89/// guard goes out of scope), the following idiom can be used:
90/// @code
91/// // 'guard' is an existing guard of type 'bslmt::WriteLockGuard<my_RLock>',
92/// // created in a scope that we do not control.
93///
94/// {
95/// // ... Do work that requires the lock.
96///
97/// // We know that the lock is no longer needed.
98///
99/// my_RLock *rlock = guard.release();
100///
101/// // 'rlock' is no longer managed, but is *still* *locked*.
102///
103/// rlock->unlock();
104///
105/// // ... Do work that does not require the lock.
106/// }
107/// @endcode
108///
109/// ## Usage {#bslmt_writelockguard-usage}
110///
111///
112/// This section illustrates intended use of this component.
113///
114/// ### Example 1: Basic Usage {#bslmt_writelockguard-example-1-basic-usage}
115///
116///
117/// Use this component to ensure that in the event of an exception or exit from
118/// any point in a given scope, the synchronization object will be properly
119/// unlocked. The following function, `errorProneFunc`, is overly complex, not
120/// exception safe, and contains a bug.
121/// @code
122/// static void errorProneFunc(my_Object *obj, my_RWLock *rwlock)
123/// {
124/// rwlock->lockWrite();
125/// if (someUpgradeCondition) {
126/// obj->someUpgradeMethod();
127/// rwlock->unlock();
128/// return; // RETURN
129/// } else if (someOtherUpgradeCondition) {
130/// obj->someOtherUpgradeMethod();
131/// // MISTAKE! forgot to unlock rwlock
132/// return; // RETURN
133/// }
134/// obj->defaultUpgradeMethod();
135/// rwlock->unlock();
136/// return;
137/// }
138/// @endcode
139/// The function can be rewritten with a cleaner and safer implementation using
140/// a guard object. The `safeFunc` function is simpler than `errorProneFunc`,
141/// is exception safe, and avoids the multiple calls to unlock that can be a
142/// source of errors.
143/// @code
144/// static void safeFunc(my_Object *obj, my_RWLock *rwlock)
145/// {
146/// bslmt::WriteLockGuard<my_RWLock> guard(rwlock);
147/// if (someUpgradeCondition) {
148/// obj->someUpgradeMethod();
149/// return; // RETURN
150/// } else if (someOtherUpgradeCondition) {
151/// obj->someOtherUpgradeMethod();
152/// // OK, rwlock is automatically unlocked
153/// return; // RETURN
154/// }
155/// obj->defaultUpgradeMethod();
156/// return;
157/// }
158/// @endcode
159/// When blocking while acquiring the lock is not desirable, one may instead use
160/// a `bslmt::WriteLockGuardTryLock` in the typical following fashion:
161/// @code
162/// /// Perform upgrade and return positive value if locking succeeds.
163/// /// Return 0 if locking fails.
164/// static int safeButNonBlockingFunc(my_Object *obj, my_RWLock *rwlock)
165/// {
166/// const int RETRIES = 1; // use higher values for higher success rate
167/// bslmt::WriteLockGuardTryLock<my_RWLock> guard(rwlock, RETRIES);
168/// if (guard.ptr()) { // rwlock is locked
169/// if (someUpgradeCondition) {
170/// obj->someUpgradeMethod();
171/// return 2; // RETURN
172/// } else if (someOtherUpgradeCondition) {
173/// obj->someOtherUpgradeMethod();
174/// return 3; // RETURN
175/// }
176/// obj->defaultUpgradeMethod();
177/// return 1; // RETURN
178/// }
179/// return 0;
180/// }
181/// @endcode
182/// If the underlying lock object provides an upgrade from a lock for read to a
183/// lock for write (as does `bslmt::ReaderWriterLock` with the
184/// `upgradeToWriteLock` function, for example), and the lock is already guarded
185/// by a `bslmt::ReadLockGuard`, then it is not necessary to transfer the guard
186/// to a `bslmt::WriteLockGuard`. In fact, a combination of
187/// `bslmt::ReadLockGuard` and `bslmt::WriteLockGuard` guarding a common lock
188/// object should probably never be needed.
189///
190/// Care must be taken so as not to interleave guard objects in such a way as to
191/// cause an illegal sequence of calls on a lock (two sequential lock calls or
192/// two sequential unlock calls on a non-recursive read/write lock).
193/// @}
194/** @} */
195/** @} */
196
197/** @addtogroup bsl
198 * @{
199 */
200/** @addtogroup bslmt
201 * @{
202 */
203/** @addtogroup bslmt_writelockguard
204 * @{
205 */
206
207#include <bslscm_version.h>
208
209
210namespace bslmt {
211
212 // ====================
213 // class WriteLockGuard
214 // ====================
215
216/// This class template implements a guard for acquisition and release of
217/// write synchronization resources (i.e., writer locks).
218///
219/// See @ref bslmt_writelockguard
220template <class T>
222
223 // DATA
224 T *d_lock_p; // lock guarded by this object (held, not owned)
225
226 private:
227 // NOT IMPLEMENTED
229 WriteLockGuard<T>& operator=(const WriteLockGuard<T>&);
230
231 public:
232 // CREATORS
233
234 /// Create a scoped guard that conditionally manages the specified
235 /// `lock` (if non-null) and invokes `lock->lockWrite()`. Supplying a null `lock` has no effect.
236 ///
237 /// \pre The behavior is undefined unless `lock`
238 /// (if non-null) is not already locked by this thread.
239 ///
240 /// \note Note that `lock` must remain valid throughout the lifetime of this guard, or
241 /// until `release` is called.
242 explicit WriteLockGuard(T *lock);
243
244 /// Create a scoped guard that conditionally manages the specified
245 /// `lock` (if non-null) and invokes `lock->lockWrite()` if the
246 /// specified `alreadyLockedFlag` is `false`. Supplying a null `lock` has no effect.
247 ///
248 /// \pre The behavior is undefined unless the state of `lock`
249 /// (if non-null) is consistent with `alreadyLockedFlag`.
250 ///
251 /// \note Note that `alreadyLockedFlag` is used to indicate whether `lock` is in an
252 /// already-locked state when passed, so if `alreadyLockedFlag` is
253 /// `true` the `lock` method will *not* be called on the supplied
254 /// `lock`. Also note that `lock` must remain valid throughout the
255 /// lifetime of this guard, or until `release` is called.
256 WriteLockGuard(T *lock, bool alreadyLockedFlag);
257
258 /// Destroy this scoped guard and invoke the `unlock` method on the
259 /// lock object under management by this guard, if any. If no lock is
260 /// currently being managed, this method has no effect.
262
263 // MANIPULATORS
264
265 /// Return the address of the modifiable lock object under management by
266 /// this guard, and release the lock from further management by this
267 /// guard. If no lock is currently being managed, return 0 with no other effect.
268 ///
269 /// \note Note that this operation does *not* unlock the lock
270 /// object (if any) that was under management.
271 T *release();
272
273 // ACCESSORS
274
275 /// Return the address of the modifiable lock object under management by
276 /// this guard, or 0 if no lock is currently being managed.
277 T *ptr() const;
278};
279
280 // ====================
281 // class LockWriteGuard
282 // ====================
283
284/// @deprecated Use @ref WriteLockGuard instead.
285///
286/// See @ref bslmt_writelockguard
287template <class T>
289
290 private:
291 // NOT IMPLEMENTED
293 LockWriteGuard<T>& operator=(const LockWriteGuard<T>&);
294
295 public:
296 // CREATORS
297
298 /// @deprecated Use @ref WriteLockGuard instead.
299 explicit LockWriteGuard(T *lock);
300
301 /// @deprecated Use @ref WriteLockGuard instead.
302 LockWriteGuard(T *lock, bool alreadyLockedFlag);
303
304};
305
306 // ==========================
307 // class WriteLockGuardUnlock
308 // ==========================
309
310/// This class template implements a guard for release and reacquisition
311/// of write synchronization resources (i.e., writer locks).
312///
313/// See @ref bslmt_writelockguard
314template <class T>
316
317 // DATA
318 T *d_lock_p; // lock guarded by this object (held, not owned)
319
320 private:
321 // NOT IMPLEMENTED
324
325 public:
326 // CREATORS
327
328 /// Create a scoped guard that conditionally manages the specified
329 /// `lock` (if non-null) and invokes `lock->unlock()`. Supplying a null `lock` has no effect.
330 ///
331 /// \pre The behavior is undefined unless `lock` (if non-null) is locked by this thread.
332 ///
333 /// \note Note that `lock` must remain
334 /// valid throughout the lifetime of this guard, or until `release` is
335 /// called.
336 explicit WriteLockGuardUnlock(T *lock);
337
338 /// Create a scoped guard that conditionally manages the specified
339 /// `lock` (if non-null) and invokes `lock->unlock()` if the specified
340 /// `alreadyUnlockedFlag` is `false`. Supplying a null `lock` has no effect.
341 ///
342 /// \pre The behavior is undefined unless the state of `lock` (if
343 /// non-null) is consistent with `alreadyUnlockedFlag`.
344 ///
345 /// \note Note that `alreadyUnlockedFlag` is used to indicate whether `lock` is in an
346 /// already-unlocked state when passed, so if `alreadyUnlockedFlag` is
347 /// `true` the `unlock` method will *not* be called on the supplied
348 /// `lock`. Also note that `lock` must remain valid throughout the
349 /// lifetime of this guard, or until `release` is called.
350 WriteLockGuardUnlock(T *lock, bool alreadyUnlockedFlag);
351
352 /// Destroy this scoped guard and invoke the `lockWrite` method on the
353 /// lock object under management by this guard, if any. If no lock is
354 /// currently being managed, this method has no effect.
356
357 // MANIPULATORS
358
359 /// Return the address of the modifiable lock object under management by
360 /// this guard, and release the lock from further management by this
361 /// guard. If no lock is currently being managed, return 0 with no other effect.
362 ///
363 /// \note Note that this operation does *not* lock the lock
364 /// object (if any) that was under management.
365 T *release();
366
367 // ACCESSORS
368
369 /// Return the address of the modifiable lock object under management by
370 /// this guard, or 0 if no lock is currently being managed.
371 T *ptr() const;
372};
373
374 // ===========================
375 // class WriteLockGuardTryLock
376 // ===========================
377
378/// This class template implements a guard for tentative acquisition and
379/// release of write synchronization resources (i.e., writer locks).
380///
381/// See @ref bslmt_writelockguard
382template <class T>
384
385 // DATA
386 T *d_lock_p; // lock guarded by this object (held, not owned)
387
388 private:
389 // NOT IMPLEMENTED
392
393 public:
394 // CREATORS
395
396 /// Create a scoped guard that conditionally manages the specified
397 /// `lock` (if non-null) and invokes `lock->tryLockWrite()` until the
398 /// lock is acquired for writing, or until the optionally specified
399 /// `attempts` have been made to acquire the lock. If `attempts` is not
400 /// specified only one attempt is made to acquire the lock. Supplying a null `lock` has no effect.
401 ///
402 /// \pre The behavior is undefined unless `lock`
403 /// (if non-null) is not already locked by this thread and `0 < attempts`.
404 ///
405 /// \note Note that `lock` must remain valid throughout the
406 /// lifetime of this guard, or until `release` is called.
407 explicit WriteLockGuardTryLock(T *lock, int attempts = 1);
408
409 /// Destroy this scoped guard and invoke the `unlock` method on the
410 /// lock object under management by this guard, if any. If no lock is
411 /// currently being managed, this method has no effect.
413
414 // MANIPULATORS
415
416 /// Return the address of the modifiable lock object under management by
417 /// this guard, and release the lock from further management by this
418 /// guard. If no lock is currently being managed, return 0 with no other effect.
419 ///
420 /// \note Note that this operation does *not* unlock the lock
421 /// object (if any) that was under management.
422 T *release();
423
424 // ACCESSORS
425
426 /// Return the address of the modifiable lock object under management by
427 /// this guard, or 0 if no lock is currently being managed.
428 T *ptr() const;
429};
430
431// ============================================================================
432// INLINE DEFINITIONS
433// ============================================================================
434
435 // --------------------
436 // class WriteLockGuard
437 // --------------------
438
439// CREATORS
440template <class T>
441inline
443: d_lock_p(lock)
444{
445 if (d_lock_p) {
446 d_lock_p->lockWrite();
447 }
448}
449
450template <class T>
451inline
452WriteLockGuard<T>::WriteLockGuard(T *lock, bool alreadyLockedFlag)
453: d_lock_p(lock)
454{
455 if (d_lock_p && !alreadyLockedFlag) {
456 d_lock_p->lockWrite();
457 }
458}
459
460template <class T>
461inline
463{
464 if (d_lock_p) {
465 d_lock_p->unlock();
466 }
467}
468
469// MANIPULATORS
470
471template <class T>
472inline
474{
475 T *lock = d_lock_p;
476 d_lock_p = 0;
477 return lock;
478}
479
480// ACCESSORS
481template <class T>
482inline
484{
485 return d_lock_p;
486}
487
488 // --------------------------
489 // class WriteLockGuardUnlock
490 // --------------------------
491
492// CREATORS
493template <class T>
494inline
496: d_lock_p(lock)
497{
498 if (d_lock_p) {
499 d_lock_p->unlock();
500 }
501}
502
503template <class T>
504inline
506 bool alreadyUnlockedFlag)
507: d_lock_p(lock)
508{
509 if (d_lock_p && !alreadyUnlockedFlag) {
510 d_lock_p->unlock();
511 }
512}
513
514template <class T>
515inline
517{
518 if (d_lock_p) {
519 d_lock_p->lockWrite();
520 }
521}
522
523// MANIPULATORS
524template <class T>
525inline
527{
528 T *lock = d_lock_p;
529 d_lock_p = 0;
530 return lock;
531}
532
533// ACCESSORS
534template <class T>
535inline
537{
538 return d_lock_p;
539}
540
541 // ---------------------------
542 // class WriteLockGuardTryLock
543 // ---------------------------
544
545// CREATORS
546template <class T>
548: d_lock_p(0)
549{
550 if (lock) {
551 while (attempts--) {
552 if (!lock->tryLockWrite()) {
553 d_lock_p = lock;
554 break;
555 }
556 }
557 }
558}
559
560template <class T>
561inline
563{
564 if (d_lock_p) {
565 d_lock_p->unlock();
566 }
567}
568
569// MANIPULATORS
570template <class T>
571inline
573{
574 T *lock = d_lock_p;
575 d_lock_p = 0;
576 return lock;
577}
578
579// ACCESSORS
580template <class T>
581inline
583{
584 return d_lock_p;
585}
586
587 // --------------------
588 // class LockWriteGuard
589 // --------------------
590
591// CREATORS
592template <class T>
593inline
595: WriteLockGuard<T>(lock)
596{
597}
598
599template <class T>
600inline
601LockWriteGuard<T>::LockWriteGuard(T *lock, bool alreadyLockedFlag)
602: WriteLockGuard<T>(lock, alreadyLockedFlag)
603{
604}
605
606} // close package namespace
607
608
609#endif
610
611// ----------------------------------------------------------------------------
612// Copyright 2015 Bloomberg Finance L.P.
613//
614// Licensed under the Apache License, Version 2.0 (the "License");
615// you may not use this file except in compliance with the License.
616// You may obtain a copy of the License at
617//
618// http://www.apache.org/licenses/LICENSE-2.0
619//
620// Unless required by applicable law or agreed to in writing, software
621// distributed under the License is distributed on an "AS IS" BASIS,
622// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
623// See the License for the specific language governing permissions and
624// limitations under the License.
625// ----------------------------- END-OF-FILE ----------------------------------
626
627/** @} */
628/** @} */
629/** @} */
Definition bslmt_writelockguard.h:288
Definition bslmt_writelockguard.h:383
~WriteLockGuardTryLock()
Definition bslmt_writelockguard.h:562
T * ptr() const
Definition bslmt_writelockguard.h:582
T * release()
Definition bslmt_writelockguard.h:572
Definition bslmt_writelockguard.h:315
T * release()
Definition bslmt_writelockguard.h:526
~WriteLockGuardUnlock()
Definition bslmt_writelockguard.h:516
T * ptr() const
Definition bslmt_writelockguard.h:536
Definition bslmt_writelockguard.h:221
~WriteLockGuard()
Definition bslmt_writelockguard.h:462
T * release()
Definition bslmt_writelockguard.h:473
T * ptr() const
Definition bslmt_writelockguard.h:483
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bslmt_barrier.h:344