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 
27 namespace 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  */
145 void
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. */
165 void
167 {
168  locked_ = false;
169  if (rawrwlock_) {
170  rawrwlock_->unlock();
171  } else {
172  refrwlock_->unlock();
173  }
174 }
175 
176 } // 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.