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