Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * scoped_rwlock.cpp - Scoped read/write lock 00004 * 00005 * Created: Mon Jan 10 11:45:49 2011 00006 * Copyright 2006-2011 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <core/threading/scoped_rwlock.h> 00025 #include <core/threading/read_write_lock.h> 00026 00027 namespace fawkes { 00028 #if 0 /* just to make Emacs auto-indent happy */ 00029 } 00030 #endif 00031 00032 /** @class ScopedRWLock <core/threading/scoped_rwlock.h> 00033 * Scoped read/write lock. 00034 * This class is a convenience class which can help you prevent quite 00035 * a few headaches. Consider the following code. 00036 * @code 00037 * void my_function() 00038 * { 00039 * rwlock->lock_for_write(); 00040 * for (int i = 0; i < LIMIT; ++i) { 00041 * if ( failure ) { 00042 * rwlock->unlock(); 00043 * } 00044 * } 00045 * 00046 * switch ( someval ) { 00047 * VALA: 00048 * rwlock->unlock(); 00049 * return; 00050 * VALB: 00051 * do_something(); 00052 * } 00053 * 00054 * try { 00055 * do_function_that_throws_exceptions(); 00056 * } catch (Exception &e) { 00057 * rwlock->unlock(); 00058 * throw; 00059 * } 00060 * rwlock->unlock(); 00061 * } 00062 * @endcode 00063 * This is not a complete list of examples but as you see if you have many 00064 * exit points in a function it becomes more and more work to have correct 00065 * locking behavior. 00066 * 00067 * This is a lot simpler with the ScopedRWLock. The ScopedRWLock locks the 00068 * given ReadWriteLock on creation, and unlocks it in the destructor. If you now 00069 * have a read/write locker on the stack as integral type the destructor is 00070 * called automagically on function exit and thus the lock is appropriately 00071 * unlocked. 00072 * The code would look like this: 00073 * @code 00074 * void my_function() 00075 * { 00076 * ScopedRWLock lock(rwlock); 00077 * // do anything, no need to call rwlock->lock_*()/unlock() if only has to be 00078 * // called on entering and exiting the function. 00079 * } 00080 * @endcode 00081 * 00082 * @ingroup Threading 00083 * @ingroup FCL 00084 * 00085 * @author Tim Niemueller 00086 */ 00087 00088 00089 /** Constructor. 00090 * @param rwlock ReadWriteLock to lock/unlock appropriately. 00091 * @param initially_lock true to lock the rwlock in the constructor, 00092 * false to not lock 00093 * @param lock_type locking type, lock either for writing or for reading 00094 */ 00095 ScopedRWLock::ScopedRWLock(RefPtr<ReadWriteLock> rwlock, ScopedRWLock::LockType lock_type, 00096 bool initially_lock) 00097 { 00098 __rawrwlock = 0; 00099 __refrwlock = rwlock; 00100 __lock_type = lock_type; 00101 if ( initially_lock ) { 00102 if (__lock_type == LOCK_WRITE) { 00103 __refrwlock->lock_for_write(); 00104 } else { 00105 __refrwlock->lock_for_read(); 00106 } 00107 } 00108 __locked = initially_lock; 00109 } 00110 00111 00112 /** Constructor. 00113 * @param rwlock ReadWriteLock to lock/unlock appropriately. 00114 * @param initially_lock true to lock the rwlock in the constructor, 00115 * false to not lock 00116 * @param lock_type locking type, lock either for writing or for reading 00117 */ 00118 ScopedRWLock::ScopedRWLock(ReadWriteLock *rwlock, ScopedRWLock::LockType lock_type, 00119 bool initially_lock) 00120 { 00121 __rawrwlock = rwlock; 00122 __lock_type = lock_type; 00123 if ( initially_lock ) { 00124 if (__lock_type == LOCK_WRITE) { 00125 __rawrwlock->lock_for_write(); 00126 } else { 00127 __rawrwlock->lock_for_read(); 00128 } 00129 } 00130 __locked = initially_lock; 00131 } 00132 00133 00134 /** Destructor */ 00135 ScopedRWLock::~ScopedRWLock() 00136 { 00137 if ( __locked ) { 00138 if ( __rawrwlock) { 00139 __rawrwlock->unlock(); 00140 } else { 00141 __refrwlock->unlock(); 00142 } 00143 } 00144 } 00145 00146 00147 /** Lock this rwlock, again. 00148 * Use this if you unlocked the rwlock from the outside. 00149 */ 00150 void 00151 ScopedRWLock::relock() 00152 { 00153 if ( __rawrwlock ) { 00154 if (__lock_type == LOCK_WRITE) { 00155 __rawrwlock->lock_for_write(); 00156 } else { 00157 __rawrwlock->lock_for_read(); 00158 } 00159 } else { 00160 if (__lock_type == LOCK_WRITE) { 00161 __refrwlock->lock_for_write(); 00162 } else { 00163 __refrwlock->lock_for_read(); 00164 } 00165 } 00166 __locked = true; 00167 } 00168 00169 00170 /** Unlock the rwlock. */ 00171 void 00172 ScopedRWLock::unlock() 00173 { 00174 __locked = false; 00175 if ( __rawrwlock ) { 00176 __rawrwlock->unlock(); 00177 } else { 00178 __refrwlock->unlock(); 00179 } 00180 } 00181 00182 00183 } // end namespace fawkes