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/scoped_rwlock.h>
25 #include <core/threading/read_write_lock.h>
26 
27 namespace fawkes {
28 #if 0 /* just to make Emacs auto-indent happy */
29 }
30 #endif
31 
32 /** @class ScopedRWLock <core/threading/scoped_rwlock.h>
33  * Scoped read/write lock.
34  * This class is a convenience class which can help you prevent quite
35  * a few headaches. Consider the following code.
36  * @code
37  * void my_function()
38  * {
39  * rwlock->lock_for_write();
40  * for (int i = 0; i < LIMIT; ++i) {
41  * if ( failure ) {
42  * rwlock->unlock();
43  * }
44  * }
45  *
46  * switch ( someval ) {
47  * VALA:
48  * rwlock->unlock();
49  * return;
50  * VALB:
51  * do_something();
52  * }
53  *
54  * try {
55  * do_function_that_throws_exceptions();
56  * } catch (Exception &e) {
57  * rwlock->unlock();
58  * throw;
59  * }
60  * rwlock->unlock();
61  * }
62  * @endcode
63  * This is not a complete list of examples but as you see if you have many
64  * exit points in a function it becomes more and more work to have correct
65  * locking behavior.
66  *
67  * This is a lot simpler with the ScopedRWLock. The ScopedRWLock locks the
68  * given ReadWriteLock on creation, and unlocks it in the destructor. If you now
69  * have a read/write locker on the stack as integral type the destructor is
70  * called automagically on function exit and thus the lock is appropriately
71  * unlocked.
72  * The code would look like this:
73  * @code
74  * void my_function()
75  * {
76  * ScopedRWLock lock(rwlock);
77  * // do anything, no need to call rwlock->lock_*()/unlock() if only has to be
78  * // called on entering and exiting the function.
79  * }
80  * @endcode
81  *
82  * @ingroup Threading
83  * @ingroup FCL
84  *
85  * @author Tim Niemueller
86  */
87 
88 
89 /** Constructor.
90  * @param rwlock ReadWriteLock to lock/unlock appropriately.
91  * @param initially_lock true to lock the rwlock in the constructor,
92  * false to not lock
93  * @param lock_type locking type, lock either for writing or for reading
94  */
96  bool initially_lock)
97 {
98  __rawrwlock = 0;
99  __refrwlock = rwlock;
100  __lock_type = lock_type;
101  if ( initially_lock ) {
102  if (__lock_type == LOCK_WRITE) {
103  __refrwlock->lock_for_write();
104  } else {
105  __refrwlock->lock_for_read();
106  }
107  }
108  __locked = initially_lock;
109 }
110 
111 
112 /** Constructor.
113  * @param rwlock ReadWriteLock to lock/unlock appropriately.
114  * @param initially_lock true to lock the rwlock in the constructor,
115  * false to not lock
116  * @param lock_type locking type, lock either for writing or for reading
117  */
119  bool initially_lock)
120 {
121  __rawrwlock = rwlock;
122  __lock_type = lock_type;
123  if ( initially_lock ) {
124  if (__lock_type == LOCK_WRITE) {
125  __rawrwlock->lock_for_write();
126  } else {
127  __rawrwlock->lock_for_read();
128  }
129  }
130  __locked = initially_lock;
131 }
132 
133 
134 /** Destructor */
136 {
137  if ( __locked ) {
138  if ( __rawrwlock) {
139  __rawrwlock->unlock();
140  } else {
141  __refrwlock->unlock();
142  }
143  }
144 }
145 
146 
147 /** Lock this rwlock, again.
148  * Use this if you unlocked the rwlock from the outside.
149  */
150 void
152 {
153  if ( __rawrwlock ) {
154  if (__lock_type == LOCK_WRITE) {
155  __rawrwlock->lock_for_write();
156  } else {
157  __rawrwlock->lock_for_read();
158  }
159  } else {
160  if (__lock_type == LOCK_WRITE) {
161  __refrwlock->lock_for_write();
162  } else {
163  __refrwlock->lock_for_read();
164  }
165  }
166  __locked = true;
167 }
168 
169 
170 /** Unlock the rwlock. */
171 void
173 {
174  __locked = false;
175  if ( __rawrwlock ) {
176  __rawrwlock->unlock();
177  } else {
178  __refrwlock->unlock();
179  }
180 }
181 
182 
183 } // end namespace fawkes
void lock_for_read()
Aquire a reader lock.
Fawkes library namespace.
void lock_for_write()
Aquire a writer lock.
ScopedRWLock(RefPtr< ReadWriteLock > rwlock, LockType lock_type=LOCK_WRITE, bool initially_lock=true)
Constructor.
Read/write lock to allow multiple readers but only a single writer on the resource at a time...
void relock()
Lock this rwlock, again.
LockType
What to lock for.
Definition: scoped_rwlock.h:37
RefPtr<> is a reference-counting shared smartpointer.
Definition: refptr.h:49
~ScopedRWLock()
Destructor.
void unlock()
Release the lock.
void unlock()
Unlock the rwlock.