Fawkes API Fawkes Development Version
scoped_rwlock.cpp
1
2/***************************************************************************
3 * scoped_rwlock.cpp - Scoped read/write lock
4 *
5 * Created: Mon Jan 10 11:45:49 2011
6 * Copyright 2006-2011 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <core/threading/read_write_lock.h>
25#include <core/threading/scoped_rwlock.h>
26
27namespace fawkes {
28
29/** @class ScopedRWLock <core/threading/scoped_rwlock.h>
30 * Scoped read/write lock.
31 * This class is a convenience class which can help you prevent quite
32 * a few headaches. Consider the following code.
33 * @code
34 * void my_function()
35 * {
36 * rwlock->lock_for_write();
37 * for (int i = 0; i < LIMIT; ++i) {
38 * if ( failure ) {
39 * rwlock->unlock();
40 * }
41 * }
42 *
43 * switch ( someval ) {
44 * VALA:
45 * rwlock->unlock();
46 * return;
47 * VALB:
48 * do_something();
49 * }
50 *
51 * try {
52 * do_function_that_throws_exceptions();
53 * } catch (Exception &e) {
54 * rwlock->unlock();
55 * throw;
56 * }
57 * rwlock->unlock();
58 * }
59 * @endcode
60 * This is not a complete list of examples but as you see if you have many
61 * exit points in a function it becomes more and more work to have correct
62 * locking behavior.
63 *
64 * This is a lot simpler with the ScopedRWLock. The ScopedRWLock locks the
65 * given ReadWriteLock on creation, and unlocks it in the destructor. If you now
66 * have a read/write locker on the stack as integral type the destructor is
67 * called automagically on function exit and thus the lock is appropriately
68 * unlocked.
69 * The code would look like this:
70 * @code
71 * void my_function()
72 * {
73 * ScopedRWLock lock(rwlock);
74 * // do anything, no need to call rwlock->lock_*()/unlock() if only has to be
75 * // called on entering and exiting the function.
76 * }
77 * @endcode
78 *
79 * @ingroup Threading
80 * @ingroup FCL
81 *
82 * @author Tim Niemueller
83 */
84
85/** Constructor.
86 * @param rwlock ReadWriteLock to lock/unlock appropriately.
87 * @param initially_lock true to lock the rwlock in the constructor,
88 * false to not lock
89 * @param lock_type locking type, lock either for writing or for reading
90 */
92 ScopedRWLock::LockType lock_type,
93 bool initially_lock)
94{
95 rawrwlock_ = 0;
96 refrwlock_ = rwlock;
97 lock_type_ = lock_type;
98 if (initially_lock) {
99 if (lock_type_ == LOCK_WRITE) {
100 refrwlock_->lock_for_write();
101 } else {
102 refrwlock_->lock_for_read();
103 }
104 }
105 locked_ = initially_lock;
106}
107
108/** Constructor.
109 * @param rwlock ReadWriteLock to lock/unlock appropriately.
110 * @param initially_lock true to lock the rwlock in the constructor,
111 * false to not lock
112 * @param lock_type locking type, lock either for writing or for reading
113 */
115 ScopedRWLock::LockType lock_type,
116 bool initially_lock)
117{
118 rawrwlock_ = rwlock;
119 lock_type_ = lock_type;
120 if (initially_lock) {
121 if (lock_type_ == LOCK_WRITE) {
122 rawrwlock_->lock_for_write();
123 } else {
124 rawrwlock_->lock_for_read();
125 }
126 }
127 locked_ = initially_lock;
128}
129
130/** Destructor */
132{
133 if (locked_) {
134 if (rawrwlock_) {
135 rawrwlock_->unlock();
136 } else {
137 refrwlock_->unlock();
138 }
139 }
140}
141
142/** Lock this rwlock, again.
143 * Use this if you unlocked the rwlock from the outside.
144 */
145void
147{
148 if (rawrwlock_) {
149 if (lock_type_ == LOCK_WRITE) {
150 rawrwlock_->lock_for_write();
151 } else {
152 rawrwlock_->lock_for_read();
153 }
154 } else {
155 if (lock_type_ == LOCK_WRITE) {
156 refrwlock_->lock_for_write();
157 } else {
158 refrwlock_->lock_for_read();
159 }
160 }
161 locked_ = true;
162}
163
164/** Unlock the rwlock. */
165void
167{
168 locked_ = false;
169 if (rawrwlock_) {
170 rawrwlock_->unlock();
171 } else {
172 refrwlock_->unlock();
173 }
174}
175
176} // end namespace fawkes
Read/write lock to allow multiple readers but only a single writer on the resource at a time.
void unlock()
Release the lock.
void lock_for_read()
Aquire a reader lock.
void lock_for_write()
Aquire a writer lock.
RefPtr<> is a reference-counting shared smartpointer.
Definition: refptr.h:50
LockType
What to lock for.
Definition: scoped_rwlock.h:37
@ LOCK_WRITE
Lock for writing.
Definition: scoped_rwlock.h:38
void relock()
Lock this rwlock, again.
ScopedRWLock(RefPtr< ReadWriteLock > rwlock, LockType lock_type=LOCK_WRITE, bool initially_lock=true)
Constructor.
void unlock()
Unlock the rwlock.
~ScopedRWLock()
Destructor.
Fawkes library namespace.