VirtualBox

source: vbox/trunk/src/VBox/Main/include/AutoLock.h@ 25282

Last change on this file since 25282 was 25282, checked in by vboxsync, 15 years ago

Main: preparation for deadlock detection: move more logic to AutoLockBase

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.9 KB
Line 
1/** @file
2 *
3 * AutoWriteLock/AutoReadLock: smart R/W semaphore wrappers
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#ifndef ____H_AUTOLOCK
23#define ____H_AUTOLOCK
24
25#include <iprt/cdefs.h>
26#include <iprt/types.h>
27#include <iprt/critsect.h>
28#include <iprt/thread.h>
29#include <iprt/semaphore.h>
30
31#include <iprt/err.h>
32#include <iprt/assert.h>
33
34#if defined(DEBUG)
35# include <iprt/asm.h> // for ASMReturnAddress
36#endif
37
38#include <iprt/semaphore.h>
39
40namespace util
41{
42
43////////////////////////////////////////////////////////////////////////////////
44//
45// LockHandle and friends
46//
47////////////////////////////////////////////////////////////////////////////////
48
49/**
50 * Abstract lock operations. See LockHandle and AutoWriteLock for details.
51 */
52class LockOps
53{
54public:
55
56 virtual ~LockOps() {}
57
58 virtual void lock() = 0;
59 virtual void unlock() = 0;
60};
61
62/**
63 * Read lock operations. See LockHandle and AutoWriteLock for details.
64 */
65class ReadLockOps : public LockOps
66{
67public:
68
69 /**
70 * Requests a read (shared) lock.
71 */
72 virtual void lockRead() = 0;
73
74 /**
75 * Releases a read (shared) lock ackquired by lockRead().
76 */
77 virtual void unlockRead() = 0;
78
79 // LockOps interface
80 void lock() { lockRead(); }
81 void unlock() { unlockRead(); }
82};
83
84/**
85 * Write lock operations. See LockHandle and AutoWriteLock for details.
86 */
87class WriteLockOps : public LockOps
88{
89public:
90
91 /**
92 * Requests a write (exclusive) lock.
93 */
94 virtual void lockWrite() = 0;
95
96 /**
97 * Releases a write (exclusive) lock ackquired by lockWrite().
98 */
99 virtual void unlockWrite() = 0;
100
101 // LockOps interface
102 void lock() { lockWrite(); }
103 void unlock() { unlockWrite(); }
104};
105
106/**
107 * Abstract read/write semaphore handle.
108 *
109 * This is a base class to implement semaphores that provide read/write locking.
110 * Subclasses must implement all pure virtual methods of this class together
111 * with pure methods of ReadLockOps and WriteLockOps classes.
112 *
113 * See the AutoWriteLock class documentation for the detailed description of
114 * read and write locks.
115 */
116class LockHandle : protected ReadLockOps, protected WriteLockOps
117{
118public:
119
120 LockHandle() {}
121 virtual ~LockHandle() {}
122
123 /**
124 * Returns @c true if the current thread holds a write lock on this
125 * read/write semaphore. Intended for debugging only.
126 */
127 virtual bool isWriteLockOnCurrentThread() const = 0;
128
129 /**
130 * Returns the current write lock level of this semaphore. The lock level
131 * determines the number of nested #lock() calls on the given semaphore
132 * handle.
133 *
134 * Note that this call is valid only when the current thread owns a write
135 * lock on the given semaphore handle and will assert otherwise.
136 */
137 virtual uint32_t writeLockLevel() const = 0;
138
139 /**
140 * Returns an interface to read lock operations of this semaphore.
141 * Used by constructors of AutoMultiLockN classes.
142 */
143 LockOps *rlock() { return (ReadLockOps *) this; }
144
145 /**
146 * Returns an interface to write lock operations of this semaphore.
147 * Used by constructors of AutoMultiLockN classes.
148 */
149 LockOps *wlock() { return (WriteLockOps *) this; }
150
151private:
152
153 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (LockHandle)
154
155 friend class AutoWriteLock;
156 friend class AutoReadLock;
157};
158
159/**
160 * Full-featured read/write semaphore handle implementation.
161 *
162 * This is an auxiliary base class for classes that need full-featured
163 * read/write locking as described in the AutoWriteLock class documentation.
164 * Instances of classes inherited from this class can be passed as arguments to
165 * the AutoWriteLock and AutoReadLock constructors.
166 */
167class RWLockHandle : public LockHandle
168{
169public:
170
171 RWLockHandle();
172 virtual ~RWLockHandle();
173
174 bool isWriteLockOnCurrentThread() const;
175
176private:
177
178 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (RWLockHandle)
179
180 void lockWrite();
181 void unlockWrite();
182 void lockRead();
183 void unlockRead();
184
185 uint32_t writeLockLevel() const;
186
187 RTSEMRW mSemRW;
188};
189
190/**
191 * Write-only semaphore handle implementation.
192 *
193 * This is an auxiliary base class for classes that need write-only (exclusive)
194 * locking and do not need read (shared) locking. This implementation uses a
195 * cheap and fast critical section for both lockWrite() and lockRead() methods
196 * which makes a lockRead() call fully equivalent to the lockWrite() call and
197 * therefore makes it pointless to use instahces of this class with
198 * AutoReadLock instances -- shared locking will not be possible anyway and
199 * any call to lock() will block if there are lock owners on other threads.
200 *
201 * Use with care only when absolutely sure that shared locks are not necessary.
202 */
203class WriteLockHandle : public LockHandle
204{
205public:
206
207 WriteLockHandle()
208 {
209 RTCritSectInit (&mCritSect);
210 }
211
212 virtual ~WriteLockHandle()
213 {
214 RTCritSectDelete (&mCritSect);
215 }
216
217 bool isWriteLockOnCurrentThread() const
218 {
219 return RTCritSectIsOwner (&mCritSect);
220 }
221
222private:
223
224 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (WriteLockHandle)
225
226 void lockWrite()
227 {
228#if defined(DEBUG)
229 RTCritSectEnterDebug (&mCritSect,
230 "WriteLockHandle::lockWrite() return address >>>",
231 0, (RTUINTPTR) ASMReturnAddress());
232#else
233 RTCritSectEnter (&mCritSect);
234#endif
235 }
236
237 void unlockWrite()
238 {
239 RTCritSectLeave (&mCritSect);
240 }
241
242 void lockRead() { lockWrite(); }
243 void unlockRead() { unlockWrite(); }
244
245 uint32_t writeLockLevel() const
246 {
247 return RTCritSectGetRecursion (&mCritSect);
248 }
249
250 mutable RTCRITSECT mCritSect;
251};
252
253////////////////////////////////////////////////////////////////////////////////
254//
255// Lockable
256//
257////////////////////////////////////////////////////////////////////////////////
258
259/**
260 * Lockable interface.
261 *
262 * This is an abstract base for classes that need read/write locking. Unlike
263 * RWLockHandle and other classes that makes the read/write semaphore a part of
264 * class data, this class allows subclasses to decide which semaphore handle to
265 * use.
266 */
267class Lockable
268{
269public:
270
271 /**
272 * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock
273 * for locking. Subclasses are allowed to return @c NULL -- in this case,
274 * the AutoWriteLock/AutoReadLock object constructed using an instance of
275 * such subclass will simply turn into no-op.
276 */
277 virtual LockHandle *lockHandle() const = 0;
278
279 /**
280 * Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>.
281 * Returns @c false if lockHandle() returns @c NULL.
282 */
283 bool isWriteLockOnCurrentThread()
284 {
285 LockHandle *h = lockHandle();
286 return h ? h->isWriteLockOnCurrentThread() : false;
287 }
288
289 /**
290 * Equivalent to <tt>#lockHandle()->rlock()</tt>.
291 * Returns @c NULL false if lockHandle() returns @c NULL.
292 */
293 LockOps *rlock()
294 {
295 LockHandle *h = lockHandle();
296 return h ? h->rlock() : NULL;
297 }
298
299 /**
300 * Equivalent to <tt>#lockHandle()->wlock()</tt>. Returns @c NULL false if
301 * lockHandle() returns @c NULL.
302 */
303 LockOps *wlock()
304 {
305 LockHandle *h = lockHandle();
306 return h ? h->wlock() : NULL;
307 }
308};
309
310////////////////////////////////////////////////////////////////////////////////
311//
312// AutoLockBase
313//
314////////////////////////////////////////////////////////////////////////////////
315
316class AutoLockBase
317{
318protected:
319 AutoLockBase(LockHandle *pHandle);
320 virtual ~AutoLockBase();
321
322 struct Data;
323 Data *m;
324
325 virtual void acquireImpl(LockHandle &l) = 0;
326 virtual void releaseImpl(LockHandle &l) = 0;
327
328public:
329 void acquire();
330 void release();
331
332private:
333 // prohibit copy + assignment
334 AutoLockBase(const AutoLockBase&);
335 AutoLockBase& operator=(AutoLockBase&);
336};
337
338////////////////////////////////////////////////////////////////////////////////
339//
340// AutoWriteLock
341//
342////////////////////////////////////////////////////////////////////////////////
343
344class AutoWriteLock : public AutoLockBase
345{
346public:
347
348 /**
349 * Constructs a null instance that does not manage any read/write
350 * semaphore.
351 *
352 * Note that all method calls on a null instance are no-ops. This allows to
353 * have the code where lock protection can be selected (or omitted) at
354 * runtime.
355 */
356 AutoWriteLock()
357 : AutoLockBase(NULL)
358 { }
359
360 /**
361 * Constructs a new instance that will start managing the given read/write
362 * semaphore by requesting a write lock.
363 */
364 AutoWriteLock(LockHandle *aHandle)
365 : AutoLockBase(aHandle)
366 {
367 acquire();
368 }
369
370 /**
371 * Constructs a new instance that will start managing the given read/write
372 * semaphore by requesting a write lock.
373 */
374 AutoWriteLock(LockHandle &aHandle)
375 : AutoLockBase(&aHandle)
376 {
377 acquire();
378 }
379
380 /**
381 * Constructs a new instance that will start managing the given read/write
382 * semaphore by requesting a write lock.
383 */
384 AutoWriteLock(const Lockable &aLockable)
385 : AutoLockBase(aLockable.lockHandle())
386 {
387 acquire();
388 }
389
390 /**
391 * Constructs a new instance that will start managing the given read/write
392 * semaphore by requesting a write lock.
393 */
394 AutoWriteLock(const Lockable *aLockable)
395 : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
396 {
397 acquire();
398 }
399
400 /**
401 * Release all write locks acquired by this instance through the #lock()
402 * call and destroys the instance.
403 *
404 * Note that if there there are nested #lock() calls without the
405 * corresponding number of #unlock() calls when the destructor is called, it
406 * will assert. This is because having an unbalanced number of nested locks
407 * is a program logic error which must be fixed.
408 */
409 virtual ~AutoWriteLock()
410 {
411 cleanup();
412 }
413
414 void cleanup();
415
416 virtual void acquireImpl(LockHandle &l);
417 virtual void releaseImpl(LockHandle &l);
418
419 void leave();
420 void enter();
421
422 /**
423 * Same as #leave() but checks if the current thread actally owns the lock
424 * and only proceeds in this case. As a result, as opposed to #leave(),
425 * doesn't assert when called with no lock being held.
426 */
427 void maybeLeave()
428 {
429 if (isWriteLockOnCurrentThread())
430 leave();
431 }
432
433 /**
434 * Same as #enter() but checks if the current thread actally owns the lock
435 * and only proceeds if not. As a result, as opposed to #enter(), doesn't
436 * assert when called with the lock already being held.
437 */
438 void maybeEnter()
439 {
440 if (!isWriteLockOnCurrentThread())
441 enter();
442 }
443
444 void attach(LockHandle *aHandle);
445
446 /** @see attach (LockHandle *) */
447 void attach(LockHandle &aHandle)
448 {
449 attach(&aHandle);
450 }
451
452 /** @see attach (LockHandle *) */
453 void attach(const Lockable &aLockable)
454 {
455 attach(aLockable.lockHandle());
456 }
457
458 /** @see attach (LockHandle *) */
459 void attach(const Lockable *aLockable)
460 {
461 attach(aLockable ? aLockable->lockHandle() : NULL);
462 }
463
464 void attachRaw(LockHandle *ph);
465
466 bool isWriteLockOnCurrentThread() const;
467 uint32_t writeLockLevel() const;
468};
469
470////////////////////////////////////////////////////////////////////////////////
471//
472// AutoReadLock
473//
474////////////////////////////////////////////////////////////////////////////////
475
476class AutoReadLock : public AutoLockBase
477{
478public:
479
480 /**
481 * Constructs a null instance that does not manage any read/write
482 * semaphore.
483 *
484 * Note that all method calls on a null instance are no-ops. This allows to
485 * have the code where lock protection can be selected (or omitted) at
486 * runtime.
487 */
488 AutoReadLock()
489 : AutoLockBase(NULL)
490 { }
491
492 /**
493 * Constructs a new instance that will start managing the given read/write
494 * semaphore by requesting a read lock.
495 */
496 AutoReadLock(LockHandle *aHandle)
497 : AutoLockBase(aHandle)
498 {
499 acquire();
500 }
501
502 /**
503 * Constructs a new instance that will start managing the given read/write
504 * semaphore by requesting a read lock.
505 */
506 AutoReadLock(LockHandle &aHandle)
507 : AutoLockBase(&aHandle)
508 {
509 acquire();
510 }
511
512 /**
513 * Constructs a new instance that will start managing the given read/write
514 * semaphore by requesting a read lock.
515 */
516 AutoReadLock(const Lockable &aLockable)
517 : AutoLockBase(aLockable.lockHandle())
518 {
519 acquire();
520 }
521
522 /**
523 * Constructs a new instance that will start managing the given read/write
524 * semaphore by requesting a read lock.
525 */
526 AutoReadLock(const Lockable *aLockable)
527 : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
528 {
529 acquire();
530 }
531
532 virtual ~AutoReadLock();
533
534 virtual void acquireImpl(LockHandle &l);
535 virtual void releaseImpl(LockHandle &l);
536};
537
538////////////////////////////////////////////////////////////////////////////////
539//
540// AutoMulti*
541//
542////////////////////////////////////////////////////////////////////////////////
543
544/**
545 * Helper template class for AutoMultiLockN classes.
546 *
547 * @param Cnt number of read/write semaphores to manage.
548 */
549template <size_t Cnt>
550class AutoMultiLockBase
551{
552public:
553
554 /**
555 * Releases all locks if not yet released by #unlock() and destroys the
556 * instance.
557 */
558 ~AutoMultiLockBase()
559 {
560 if (mIsLocked)
561 unlock();
562 }
563
564 /**
565 * Calls LockOps::lock() methods of all managed semaphore handles
566 * in order they were passed to the constructor.
567 *
568 * Note that as opposed to LockHandle::lock(), this call cannot be nested
569 * and will assert if so.
570 */
571 void lock()
572 {
573 AssertReturnVoid (!mIsLocked);
574
575 size_t i = 0;
576 while (i < RT_ELEMENTS (mOps))
577 if (mOps [i])
578 mOps [i ++]->lock();
579 mIsLocked = true;
580 }
581
582 /**
583 * Calls LockOps::unlock() methods of all managed semaphore handles in
584 * reverse to the order they were passed to the constructor.
585 *
586 * Note that as opposed to LockHandle::unlock(), this call cannot be nested
587 * and will assert if so.
588 */
589 void unlock()
590 {
591 AssertReturnVoid (mIsLocked);
592
593 AssertReturnVoid (RT_ELEMENTS (mOps) > 0);
594 size_t i = RT_ELEMENTS (mOps);
595 do
596 if (mOps [-- i])
597 mOps [i]->unlock();
598 while (i != 0);
599 mIsLocked = false;
600 }
601
602protected:
603
604 AutoMultiLockBase() : mIsLocked (false) {}
605
606 LockOps *mOps [Cnt];
607 bool mIsLocked;
608
609private:
610
611 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiLockBase)
612 DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiLockBase)
613};
614
615/** AutoMultiLockBase <0> is meaningless and forbidden. */
616template<>
617class AutoMultiLockBase <0> { private : AutoMultiLockBase(); };
618
619/** AutoMultiLockBase <1> is meaningless and forbidden. */
620template<>
621class AutoMultiLockBase <1> { private : AutoMultiLockBase(); };
622
623////////////////////////////////////////////////////////////////////////////////
624
625/* AutoMultiLockN class definitions */
626
627#define A(n) LockOps *l##n
628#define B(n) mOps [n] = l##n
629
630/**
631 * AutoMultiLock for 2 locks.
632 *
633 * The AutoMultiLockN family of classes provides a possibility to manage several
634 * read/write semaphores at once. This is handy if all managed semaphores need
635 * to be locked and unlocked synchronously and will also help to avoid locking
636 * order errors.
637 *
638 * Instances of AutoMultiLockN classes are constructed from a list of LockOps
639 * arguments. The AutoMultiLockBase::lock() method will make sure that the given
640 * list of semaphores represented by LockOps pointers will be locked in order
641 * they are passed to the constructor. The AutoMultiLockBase::unlock() method
642 * will make sure that they will be unlocked in reverse order.
643 *
644 * The type of the lock to request is specified for each semaphore individually
645 * using the corresponding LockOps getter of a LockHandle or Lockable object:
646 * LockHandle::wlock() in order to request a write lock or LockHandle::rlock()
647 * in order to request a read lock.
648 *
649 * Here is a typical usage pattern:
650 * <code>
651 * ...
652 * LockHandle data1, data2;
653 * ...
654 * {
655 * AutoMultiLock2 multiLock (data1.wlock(), data2.rlock());
656 * // both locks are held here:
657 * // - data1 is locked in write mode (like AutoWriteLock)
658 * // - data2 is locked in read mode (like AutoReadLock)
659 * }
660 * // both locks are released here
661 * </code>
662 */
663class AutoMultiLock2 : public AutoMultiLockBase <2>
664{
665public:
666 AutoMultiLock2 (A(0), A(1))
667 { B(0); B(1); lock(); }
668};
669
670/** AutoMultiLock for 3 locks. See AutoMultiLock2 for more information. */
671class AutoMultiLock3 : public AutoMultiLockBase <3>
672{
673public:
674 AutoMultiLock3 (A(0), A(1), A(2))
675 { B(0); B(1); B(2); lock(); }
676};
677
678/** AutoMultiLock for 4 locks. See AutoMultiLock2 for more information. */
679class AutoMultiLock4 : public AutoMultiLockBase <4>
680{
681public:
682 AutoMultiLock4 (A(0), A(1), A(2), A(3))
683 { B(0); B(1); B(2); B(3); lock(); }
684};
685
686#undef B
687#undef A
688
689////////////////////////////////////////////////////////////////////////////////
690
691/**
692 * Helper template class for AutoMultiWriteLockN classes.
693 *
694 * @param Cnt number of write semaphores to manage.
695 */
696template <size_t Cnt>
697class AutoMultiWriteLockBase
698{
699
700public:
701 /**
702 * Calls AutoWriteLock::acquire() methods for all managed semaphore handles in
703 * order they were passed to the constructor.
704 */
705 void acquire()
706 {
707 size_t i = 0;
708 while (i < RT_ELEMENTS(mLocks))
709 mLocks[i++].acquire();
710 }
711
712 /**
713 * Calls AutoWriteLock::unlock() methods for all managed semaphore handles
714 * in reverse to the order they were passed to the constructor.
715 */
716 void release()
717 {
718 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
719 size_t i = RT_ELEMENTS(mLocks);
720 do
721 mLocks[--i].release();
722 while (i != 0);
723 }
724
725 /**
726 * Calls AutoWriteLock::leave() methods for all managed semaphore handles in
727 * reverse to the order they were passed to the constructor.
728 */
729 void leave()
730 {
731 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
732 size_t i = RT_ELEMENTS(mLocks);
733 do
734 mLocks[--i].leave();
735 while (i != 0);
736 }
737
738 /**
739 * Calls AutoWriteLock::maybeLeave() methods for all managed semaphore
740 * handles in reverse to the order they were passed to the constructor.
741 */
742 void maybeLeave()
743 {
744 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
745 size_t i = RT_ELEMENTS(mLocks);
746 do
747 mLocks [-- i].maybeLeave();
748 while (i != 0);
749 }
750
751 /**
752 * Calls AutoWriteLock::maybeEnter() methods for all managed semaphore
753 * handles in order they were passed to the constructor.
754 */
755 void maybeEnter()
756 {
757 size_t i = 0;
758 while (i < RT_ELEMENTS(mLocks))
759 mLocks[i++].maybeEnter();
760 }
761
762 /**
763 * Calls AutoWriteLock::enter() methods for all managed semaphore handles in
764 * order they were passed to the constructor.
765 */
766 void enter()
767 {
768 size_t i = 0;
769 while (i < RT_ELEMENTS(mLocks))
770 mLocks[i++].enter();
771 }
772
773protected:
774
775 AutoMultiWriteLockBase() {}
776
777 void setLockHandle(size_t aIdx, LockHandle *aHandle)
778 {
779 mLocks[aIdx].attachRaw(aHandle);
780 }
781
782private:
783
784 AutoWriteLock mLocks[Cnt];
785
786 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiWriteLockBase)
787 DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiWriteLockBase)
788};
789
790/** AutoMultiWriteLockBase <0> is meaningless and forbidden. */
791template<>
792class AutoMultiWriteLockBase <0> { private : AutoMultiWriteLockBase(); };
793
794/** AutoMultiWriteLockBase <1> is meaningless and forbidden. */
795template<>
796class AutoMultiWriteLockBase <1> { private : AutoMultiWriteLockBase(); };
797
798////////////////////////////////////////////////////////////////////////////////
799
800/* AutoMultiLockN class definitions */
801
802#define A(n) LockHandle *l##n
803#define B(n) setLockHandle (n, l##n)
804
805#define C(n) Lockable *l##n
806#define D(n) setLockHandle (n, l##n ? l##n->lockHandle() : NULL)
807
808/**
809 * AutoMultiWriteLock for 2 locks.
810 *
811 * The AutoMultiWriteLockN family of classes provides a possibility to manage
812 * several read/write semaphores at once. This is handy if all managed
813 * semaphores need to be locked and unlocked synchronously and will also help to
814 * avoid locking order errors.
815 *
816 * The functionality of the AutoMultiWriteLockN class family is similar to the
817 * functionality of the AutoMultiLockN class family (see the AutoMultiLock2
818 * class for details) with two important differences:
819 * <ol>
820 * <li>Instances of AutoMultiWriteLockN classes are constructed from a list
821 * of LockHandle or Lockable arguments directly instead of getting
822 * intermediate LockOps interface pointers.
823 * </li>
824 * <li>All locks are requested in <b>write</b> mode.
825 * </li>
826 * <li>Since all locks are requested in write mode, bulk
827 * AutoMultiWriteLockBase::leave() and AutoMultiWriteLockBase::enter()
828 * operations are also available, that will leave and enter all managed
829 * semaphores at once in the proper order (similarly to
830 * AutoMultiWriteLockBase::lock() and AutoMultiWriteLockBase::unlock()).
831 * </li>
832 * </ol>
833 *
834 * Here is a typical usage pattern:
835 * <code>
836 * ...
837 * LockHandle data1, data2;
838 * ...
839 * {
840 * AutoMultiWriteLock2 multiLock (&data1, &data2);
841 * // both locks are held in write mode here
842 * }
843 * // both locks are released here
844 * </code>
845 */
846class AutoMultiWriteLock2 : public AutoMultiWriteLockBase <2>
847{
848public:
849 AutoMultiWriteLock2 (A(0), A(1))
850 { B(0); B(1); acquire(); }
851 AutoMultiWriteLock2 (C(0), C(1))
852 { D(0); D(1); acquire(); }
853};
854
855/** AutoMultiWriteLock for 3 locks. See AutoMultiWriteLock2 for more details. */
856class AutoMultiWriteLock3 : public AutoMultiWriteLockBase <3>
857{
858public:
859 AutoMultiWriteLock3 (A(0), A(1), A(2))
860 { B(0); B(1); B(2); acquire(); }
861 AutoMultiWriteLock3 (C(0), C(1), C(2))
862 { D(0); D(1); D(2); acquire(); }
863};
864
865/** AutoMultiWriteLock for 4 locks. See AutoMultiWriteLock2 for more details. */
866class AutoMultiWriteLock4 : public AutoMultiWriteLockBase <4>
867{
868public:
869 AutoMultiWriteLock4 (A(0), A(1), A(2), A(3))
870 { B(0); B(1); B(2); B(3); acquire(); }
871 AutoMultiWriteLock4 (C(0), C(1), C(2), C(3))
872 { D(0); D(1); D(2); D(3); acquire(); }
873};
874
875#undef D
876#undef C
877#undef B
878#undef A
879
880} /* namespace util */
881
882#endif // ____H_AUTOLOCK
883
884/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette