VirtualBox

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

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

Main: preparation for deadlock detection: add handles vector to AutoLockBase in preparation for AutoMulti* conversion

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.0 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 callLockImpl(LockHandle &l) = 0;
326 virtual void callUnlockImpl(LockHandle &l) = 0;
327
328 void callLockOnAllHandles();
329 void callUnlockOnAllHandles();
330
331 void cleanup();
332
333public:
334 void acquire();
335 void release();
336
337private:
338 // prohibit copy + assignment
339 AutoLockBase(const AutoLockBase&);
340 AutoLockBase& operator=(AutoLockBase&);
341};
342
343////////////////////////////////////////////////////////////////////////////////
344//
345// AutoWriteLock
346//
347////////////////////////////////////////////////////////////////////////////////
348
349class AutoWriteLock : public AutoLockBase
350{
351public:
352
353 /**
354 * Constructs a null instance that does not manage any read/write
355 * semaphore.
356 *
357 * Note that all method calls on a null instance are no-ops. This allows to
358 * have the code where lock protection can be selected (or omitted) at
359 * runtime.
360 */
361 AutoWriteLock()
362 : AutoLockBase(NULL)
363 { }
364
365 /**
366 * Constructs a new instance that will start managing the given read/write
367 * semaphore by requesting a write lock.
368 */
369 AutoWriteLock(LockHandle *aHandle)
370 : AutoLockBase(aHandle)
371 {
372 acquire();
373 }
374
375 /**
376 * Constructs a new instance that will start managing the given read/write
377 * semaphore by requesting a write lock.
378 */
379 AutoWriteLock(LockHandle &aHandle)
380 : AutoLockBase(&aHandle)
381 {
382 acquire();
383 }
384
385 /**
386 * Constructs a new instance that will start managing the given read/write
387 * semaphore by requesting a write lock.
388 */
389 AutoWriteLock(const Lockable &aLockable)
390 : AutoLockBase(aLockable.lockHandle())
391 {
392 acquire();
393 }
394
395 /**
396 * Constructs a new instance that will start managing the given read/write
397 * semaphore by requesting a write lock.
398 */
399 AutoWriteLock(const Lockable *aLockable)
400 : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
401 {
402 acquire();
403 }
404
405 /**
406 * Release all write locks acquired by this instance through the #lock()
407 * call and destroys the instance.
408 *
409 * Note that if there there are nested #lock() calls without the
410 * corresponding number of #unlock() calls when the destructor is called, it
411 * will assert. This is because having an unbalanced number of nested locks
412 * is a program logic error which must be fixed.
413 */
414 virtual ~AutoWriteLock()
415 {
416 cleanup();
417 }
418
419 virtual void callLockImpl(LockHandle &l);
420 virtual void callUnlockImpl(LockHandle &l);
421
422 void leave();
423 void enter();
424
425 /**
426 * Same as #leave() but checks if the current thread actally owns the lock
427 * and only proceeds in this case. As a result, as opposed to #leave(),
428 * doesn't assert when called with no lock being held.
429 */
430 void maybeLeave()
431 {
432 if (isWriteLockOnCurrentThread())
433 leave();
434 }
435
436 /**
437 * Same as #enter() but checks if the current thread actally owns the lock
438 * and only proceeds if not. As a result, as opposed to #enter(), doesn't
439 * assert when called with the lock already being held.
440 */
441 void maybeEnter()
442 {
443 if (!isWriteLockOnCurrentThread())
444 enter();
445 }
446
447 void attach(LockHandle *aHandle);
448
449 /** @see attach (LockHandle *) */
450 void attach(LockHandle &aHandle)
451 {
452 attach(&aHandle);
453 }
454
455 /** @see attach (LockHandle *) */
456 void attach(const Lockable &aLockable)
457 {
458 attach(aLockable.lockHandle());
459 }
460
461 /** @see attach (LockHandle *) */
462 void attach(const Lockable *aLockable)
463 {
464 attach(aLockable ? aLockable->lockHandle() : NULL);
465 }
466
467 void attachRaw(LockHandle *ph);
468
469 bool isWriteLockOnCurrentThread() const;
470 uint32_t writeLockLevel() const;
471};
472
473////////////////////////////////////////////////////////////////////////////////
474//
475// AutoReadLock
476//
477////////////////////////////////////////////////////////////////////////////////
478
479class AutoReadLock : public AutoLockBase
480{
481public:
482
483 /**
484 * Constructs a null instance that does not manage any read/write
485 * semaphore.
486 *
487 * Note that all method calls on a null instance are no-ops. This allows to
488 * have the code where lock protection can be selected (or omitted) at
489 * runtime.
490 */
491 AutoReadLock()
492 : AutoLockBase(NULL)
493 { }
494
495 /**
496 * Constructs a new instance that will start managing the given read/write
497 * semaphore by requesting a read lock.
498 */
499 AutoReadLock(LockHandle *aHandle)
500 : AutoLockBase(aHandle)
501 {
502 acquire();
503 }
504
505 /**
506 * Constructs a new instance that will start managing the given read/write
507 * semaphore by requesting a read lock.
508 */
509 AutoReadLock(LockHandle &aHandle)
510 : AutoLockBase(&aHandle)
511 {
512 acquire();
513 }
514
515 /**
516 * Constructs a new instance that will start managing the given read/write
517 * semaphore by requesting a read lock.
518 */
519 AutoReadLock(const Lockable &aLockable)
520 : AutoLockBase(aLockable.lockHandle())
521 {
522 acquire();
523 }
524
525 /**
526 * Constructs a new instance that will start managing the given read/write
527 * semaphore by requesting a read lock.
528 */
529 AutoReadLock(const Lockable *aLockable)
530 : AutoLockBase(aLockable ? aLockable->lockHandle() : NULL)
531 {
532 acquire();
533 }
534
535 virtual ~AutoReadLock();
536
537 virtual void callLockImpl(LockHandle &l);
538 virtual void callUnlockImpl(LockHandle &l);
539};
540
541////////////////////////////////////////////////////////////////////////////////
542//
543// AutoMulti*
544//
545////////////////////////////////////////////////////////////////////////////////
546
547/**
548 * Helper template class for AutoMultiLockN classes.
549 *
550 * @param Cnt number of read/write semaphores to manage.
551 */
552template <size_t Cnt>
553class AutoMultiLockBase
554{
555public:
556
557 /**
558 * Releases all locks if not yet released by #unlock() and destroys the
559 * instance.
560 */
561 ~AutoMultiLockBase()
562 {
563 if (mIsLocked)
564 unlock();
565 }
566
567 /**
568 * Calls LockOps::lock() methods of all managed semaphore handles
569 * in order they were passed to the constructor.
570 *
571 * Note that as opposed to LockHandle::lock(), this call cannot be nested
572 * and will assert if so.
573 */
574 void lock()
575 {
576 AssertReturnVoid (!mIsLocked);
577
578 size_t i = 0;
579 while (i < RT_ELEMENTS (mOps))
580 if (mOps [i])
581 mOps [i ++]->lock();
582 mIsLocked = true;
583 }
584
585 /**
586 * Calls LockOps::unlock() methods of all managed semaphore handles in
587 * reverse to the order they were passed to the constructor.
588 *
589 * Note that as opposed to LockHandle::unlock(), this call cannot be nested
590 * and will assert if so.
591 */
592 void unlock()
593 {
594 AssertReturnVoid (mIsLocked);
595
596 AssertReturnVoid (RT_ELEMENTS (mOps) > 0);
597 size_t i = RT_ELEMENTS (mOps);
598 do
599 if (mOps [-- i])
600 mOps [i]->unlock();
601 while (i != 0);
602 mIsLocked = false;
603 }
604
605protected:
606
607 AutoMultiLockBase() : mIsLocked (false) {}
608
609 LockOps *mOps [Cnt];
610 bool mIsLocked;
611
612private:
613
614 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiLockBase)
615 DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiLockBase)
616};
617
618/** AutoMultiLockBase <0> is meaningless and forbidden. */
619template<>
620class AutoMultiLockBase <0> { private : AutoMultiLockBase(); };
621
622/** AutoMultiLockBase <1> is meaningless and forbidden. */
623template<>
624class AutoMultiLockBase <1> { private : AutoMultiLockBase(); };
625
626////////////////////////////////////////////////////////////////////////////////
627
628/* AutoMultiLockN class definitions */
629
630#define A(n) LockOps *l##n
631#define B(n) mOps [n] = l##n
632
633/**
634 * AutoMultiLock for 2 locks.
635 *
636 * The AutoMultiLockN family of classes provides a possibility to manage several
637 * read/write semaphores at once. This is handy if all managed semaphores need
638 * to be locked and unlocked synchronously and will also help to avoid locking
639 * order errors.
640 *
641 * Instances of AutoMultiLockN classes are constructed from a list of LockOps
642 * arguments. The AutoMultiLockBase::lock() method will make sure that the given
643 * list of semaphores represented by LockOps pointers will be locked in order
644 * they are passed to the constructor. The AutoMultiLockBase::unlock() method
645 * will make sure that they will be unlocked in reverse order.
646 *
647 * The type of the lock to request is specified for each semaphore individually
648 * using the corresponding LockOps getter of a LockHandle or Lockable object:
649 * LockHandle::wlock() in order to request a write lock or LockHandle::rlock()
650 * in order to request a read lock.
651 *
652 * Here is a typical usage pattern:
653 * <code>
654 * ...
655 * LockHandle data1, data2;
656 * ...
657 * {
658 * AutoMultiLock2 multiLock (data1.wlock(), data2.rlock());
659 * // both locks are held here:
660 * // - data1 is locked in write mode (like AutoWriteLock)
661 * // - data2 is locked in read mode (like AutoReadLock)
662 * }
663 * // both locks are released here
664 * </code>
665 */
666class AutoMultiLock2 : public AutoMultiLockBase <2>
667{
668public:
669 AutoMultiLock2 (A(0), A(1))
670 { B(0); B(1); lock(); }
671};
672
673/** AutoMultiLock for 3 locks. See AutoMultiLock2 for more information. */
674class AutoMultiLock3 : public AutoMultiLockBase <3>
675{
676public:
677 AutoMultiLock3 (A(0), A(1), A(2))
678 { B(0); B(1); B(2); lock(); }
679};
680
681/** AutoMultiLock for 4 locks. See AutoMultiLock2 for more information. */
682class AutoMultiLock4 : public AutoMultiLockBase <4>
683{
684public:
685 AutoMultiLock4 (A(0), A(1), A(2), A(3))
686 { B(0); B(1); B(2); B(3); lock(); }
687};
688
689#undef B
690#undef A
691
692////////////////////////////////////////////////////////////////////////////////
693
694/**
695 * Helper template class for AutoMultiWriteLockN classes.
696 *
697 * @param Cnt number of write semaphores to manage.
698 */
699template <size_t Cnt>
700class AutoMultiWriteLockBase
701{
702
703public:
704 /**
705 * Calls AutoWriteLock::acquire() methods for all managed semaphore handles in
706 * order they were passed to the constructor.
707 */
708 void acquire()
709 {
710 size_t i = 0;
711 while (i < RT_ELEMENTS(mLocks))
712 mLocks[i++].acquire();
713 }
714
715 /**
716 * Calls AutoWriteLock::unlock() methods for all managed semaphore handles
717 * in reverse to the order they were passed to the constructor.
718 */
719 void release()
720 {
721 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
722 size_t i = RT_ELEMENTS(mLocks);
723 do
724 mLocks[--i].release();
725 while (i != 0);
726 }
727
728 /**
729 * Calls AutoWriteLock::leave() methods for all managed semaphore handles in
730 * reverse to the order they were passed to the constructor.
731 */
732 void leave()
733 {
734 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
735 size_t i = RT_ELEMENTS(mLocks);
736 do
737 mLocks[--i].leave();
738 while (i != 0);
739 }
740
741 /**
742 * Calls AutoWriteLock::maybeLeave() methods for all managed semaphore
743 * handles in reverse to the order they were passed to the constructor.
744 */
745 void maybeLeave()
746 {
747 AssertReturnVoid(RT_ELEMENTS(mLocks) > 0);
748 size_t i = RT_ELEMENTS(mLocks);
749 do
750 mLocks [-- i].maybeLeave();
751 while (i != 0);
752 }
753
754 /**
755 * Calls AutoWriteLock::maybeEnter() methods for all managed semaphore
756 * handles in order they were passed to the constructor.
757 */
758 void maybeEnter()
759 {
760 size_t i = 0;
761 while (i < RT_ELEMENTS(mLocks))
762 mLocks[i++].maybeEnter();
763 }
764
765 /**
766 * Calls AutoWriteLock::enter() methods for all managed semaphore handles in
767 * order they were passed to the constructor.
768 */
769 void enter()
770 {
771 size_t i = 0;
772 while (i < RT_ELEMENTS(mLocks))
773 mLocks[i++].enter();
774 }
775
776protected:
777
778 AutoMultiWriteLockBase() {}
779
780 void setLockHandle(size_t aIdx, LockHandle *aHandle)
781 {
782 mLocks[aIdx].attachRaw(aHandle);
783 }
784
785private:
786
787 AutoWriteLock mLocks[Cnt];
788
789 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (AutoMultiWriteLockBase)
790 DECLARE_CLS_NEW_DELETE_NOOP (AutoMultiWriteLockBase)
791};
792
793/** AutoMultiWriteLockBase <0> is meaningless and forbidden. */
794template<>
795class AutoMultiWriteLockBase <0> { private : AutoMultiWriteLockBase(); };
796
797/** AutoMultiWriteLockBase <1> is meaningless and forbidden. */
798template<>
799class AutoMultiWriteLockBase <1> { private : AutoMultiWriteLockBase(); };
800
801////////////////////////////////////////////////////////////////////////////////
802
803/* AutoMultiLockN class definitions */
804
805#define A(n) LockHandle *l##n
806#define B(n) setLockHandle (n, l##n)
807
808#define C(n) Lockable *l##n
809#define D(n) setLockHandle (n, l##n ? l##n->lockHandle() : NULL)
810
811/**
812 * AutoMultiWriteLock for 2 locks.
813 *
814 * The AutoMultiWriteLockN family of classes provides a possibility to manage
815 * several read/write semaphores at once. This is handy if all managed
816 * semaphores need to be locked and unlocked synchronously and will also help to
817 * avoid locking order errors.
818 *
819 * The functionality of the AutoMultiWriteLockN class family is similar to the
820 * functionality of the AutoMultiLockN class family (see the AutoMultiLock2
821 * class for details) with two important differences:
822 * <ol>
823 * <li>Instances of AutoMultiWriteLockN classes are constructed from a list
824 * of LockHandle or Lockable arguments directly instead of getting
825 * intermediate LockOps interface pointers.
826 * </li>
827 * <li>All locks are requested in <b>write</b> mode.
828 * </li>
829 * <li>Since all locks are requested in write mode, bulk
830 * AutoMultiWriteLockBase::leave() and AutoMultiWriteLockBase::enter()
831 * operations are also available, that will leave and enter all managed
832 * semaphores at once in the proper order (similarly to
833 * AutoMultiWriteLockBase::lock() and AutoMultiWriteLockBase::unlock()).
834 * </li>
835 * </ol>
836 *
837 * Here is a typical usage pattern:
838 * <code>
839 * ...
840 * LockHandle data1, data2;
841 * ...
842 * {
843 * AutoMultiWriteLock2 multiLock (&data1, &data2);
844 * // both locks are held in write mode here
845 * }
846 * // both locks are released here
847 * </code>
848 */
849class AutoMultiWriteLock2 : public AutoMultiWriteLockBase <2>
850{
851public:
852 AutoMultiWriteLock2 (A(0), A(1))
853 { B(0); B(1); acquire(); }
854 AutoMultiWriteLock2 (C(0), C(1))
855 { D(0); D(1); acquire(); }
856};
857
858/** AutoMultiWriteLock for 3 locks. See AutoMultiWriteLock2 for more details. */
859class AutoMultiWriteLock3 : public AutoMultiWriteLockBase <3>
860{
861public:
862 AutoMultiWriteLock3 (A(0), A(1), A(2))
863 { B(0); B(1); B(2); acquire(); }
864 AutoMultiWriteLock3 (C(0), C(1), C(2))
865 { D(0); D(1); D(2); acquire(); }
866};
867
868/** AutoMultiWriteLock for 4 locks. See AutoMultiWriteLock2 for more details. */
869class AutoMultiWriteLock4 : public AutoMultiWriteLockBase <4>
870{
871public:
872 AutoMultiWriteLock4 (A(0), A(1), A(2), A(3))
873 { B(0); B(1); B(2); B(3); acquire(); }
874 AutoMultiWriteLock4 (C(0), C(1), C(2), C(3))
875 { D(0); D(1); D(2); D(3); acquire(); }
876};
877
878#undef D
879#undef C
880#undef B
881#undef A
882
883} /* namespace util */
884
885#endif // ____H_AUTOLOCK
886
887/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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