1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_ 29 #define __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_ 30 31 //_________________________________________________________________________________________________________________ 32 // my own includes 33 //_________________________________________________________________________________________________________________ 34 35 #include <threadhelp/inoncopyable.h> 36 #include <threadhelp/irwlock.h> 37 #include <macros/debug.hxx> 38 39 //_________________________________________________________________________________________________________________ 40 // interface includes 41 //_________________________________________________________________________________________________________________ 42 #include <com/sun/star/uno/XInterface.hpp> 43 44 //_________________________________________________________________________________________________________________ 45 // other includes 46 //_________________________________________________________________________________________________________________ 47 #include <osl/mutex.hxx> 48 #include <osl/conditn.hxx> 49 50 //_________________________________________________________________________________________________________________ 51 // namespace 52 //_________________________________________________________________________________________________________________ 53 54 namespace framework{ 55 56 //_________________________________________________________________________________________________________________ 57 // const 58 //_________________________________________________________________________________________________________________ 59 60 //_________________________________________________________________________________________________________________ 61 // declarations 62 //_________________________________________________________________________________________________________________ 63 64 /*-************************************************************************************************************//** 65 @short implement a read/write lock with fairness between read/write accessors 66 @descr These implementation never should used as base class! Use it as a member every time. 67 Use ReadGuard and/or WriteGuard in your methods (which work with these lock) 68 to make your code threadsafe. 69 Fair means: All reading or writing threads are synchronized AND serialzed by using one 70 mutex. For reader this mutex is used to access internal variables of this lock only; 71 for writer this mutex is used to have an exclusiv access on your class member! 72 => It's a multi-reader/single-writer lock, which no preferred accessor. 73 74 @implements IRWlock 75 @base INonCopyable 76 IRWLock 77 78 @devstatus ready to use 79 *//*-*************************************************************************************************************/ 80 class FairRWLock : public IRWLock 81 , private INonCopyable 82 { 83 //------------------------------------------------------------------------------------------------------------- 84 // public methods 85 //------------------------------------------------------------------------------------------------------------- 86 public: 87 88 /*-****************************************************************************************************//** 89 @short standard ctor 90 @descr Initialize instance with right start values for correct working. 91 no reader could exist => m_nReadCount = 0 92 don't block first comming writer => m_aWriteCondition.set() 93 94 @seealso - 95 96 @param - 97 @return - 98 99 @onerror - 100 *//*-*****************************************************************************************************/ 101 inline FairRWLock() 102 : m_nReadCount( 0 ) 103 { 104 m_aWriteCondition.set(); 105 } 106 107 inline virtual ~FairRWLock() 108 { 109 } 110 111 /*-****************************************************************************************************//** 112 @interface IRWLock 113 @short set lock for reading 114 @descr A guard should call this method to acquire read access on your member. 115 Writing isn't allowed then - but nobody could check it for you! 116 117 @seealso method releaseReadAccess() 118 119 @param - 120 @return - 121 122 @onerror - 123 *//*-*****************************************************************************************************/ 124 inline virtual void acquireReadAccess() 125 { 126 // Put call in "SERIALIZE"-queue! 127 // After successful acquiring this mutex we are alone ... 128 ::osl::MutexGuard aSerializeGuard( m_aSerializer ); 129 130 // ... but we should synchronize us with other reader! 131 // May be - they will unregister himself by using releaseReadAccess()! 132 ::osl::MutexGuard aAccessGuard( m_aAccessLock ); 133 134 // Now we must register us as reader by increasing counter. 135 // If this the first writer we must close door for possible writer. 136 // Other reader don't look for this barrier - they work parallel to us! 137 if( m_nReadCount == 0 ) 138 { 139 m_aWriteCondition.reset(); 140 } 141 ++m_nReadCount; 142 } 143 144 /*-****************************************************************************************************//** 145 @interface IRWLock 146 @short reset lock for reading 147 @descr A guard should call this method to release read access on your member. 148 149 @seealso method acquireReadAccess() 150 151 @param - 152 @return - 153 154 @onerror - 155 *//*-*****************************************************************************************************/ 156 inline virtual void releaseReadAccess() 157 { 158 // The access lock is enough at this point 159 // because it's not allowed to wait for all reader or writer here! 160 // That will cause a deadlock! 161 ::osl::MutexGuard aAccessGuard( m_aAccessLock ); 162 163 // Unregister as reader first! 164 // Open writer barrier then if it was the last reader. 165 --m_nReadCount; 166 if( m_nReadCount == 0 ) 167 { 168 m_aWriteCondition.set(); 169 } 170 } 171 172 /*-****************************************************************************************************//** 173 @interface IRWLock 174 @short set lock for writing 175 @descr A guard should call this method to acquire write access on your member. 176 Reading is allowed too - of course. 177 After successfully calling of this method you are the only writer. 178 179 @seealso method releaseWriteAccess() 180 181 @param - 182 @return - 183 184 @onerror - 185 *//*-*****************************************************************************************************/ 186 inline virtual void acquireWriteAccess() 187 { 188 // You have to stand in our serialize-queue till all reader 189 // are registered (not for releasing them!) or writer finished their work! 190 // Don't use a guard to do so - because you must hold the mutex till 191 // you call releaseWriteAccess()! 192 // After succesfull acquire you have to wait for current working reader. 193 // Used condition will open by last gone reader object. 194 m_aSerializer.acquire(); 195 m_aWriteCondition.wait(); 196 197 #ifdef ENABLE_MUTEXDEBUG 198 // A writer is an exclusiv accessor! 199 LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::acquireWriteAccess()", "No threadsafe code detected ... : Read count != 0!" ) 200 #endif 201 } 202 203 /*-****************************************************************************************************//** 204 @interface IRWLock 205 @short reset lock for writing 206 @descr A guard should call this method to release write access on your member. 207 208 @seealso method acquireWriteAccess() 209 210 @param - 211 @return - 212 213 @onerror - 214 *//*-*****************************************************************************************************/ 215 inline virtual void releaseWriteAccess() 216 { 217 // The only one you have to do here is to release 218 // hold seriliaze-mutex. All other user of these instance are blocked 219 // by these mutex! 220 // You don't need any other mutex here - you are the only one in the moment! 221 222 #ifdef ENABLE_MUTEXDEBUG 223 // A writer is an exclusiv accessor! 224 LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::releaseWriteAccess()", "No threadsafe code detected ... : Read count != 0!" ) 225 #endif 226 227 m_aSerializer.release(); 228 } 229 230 /*-****************************************************************************************************//** 231 @interface IRWLock 232 @short downgrade a write access to a read access 233 @descr A guard should call this method to change a write to a read access. 234 New readers can work too - new writer are blocked! 235 236 @attention Don't call this method if you are not a writer! 237 Results are not defined then ... 238 An upgrade can't be implemented realy ... because acquiring new access 239 will be the same - there no differences! 240 241 @seealso - 242 243 @param - 244 @return - 245 246 @onerror - 247 *//*-*****************************************************************************************************/ 248 inline virtual void downgradeWriteAccess() 249 { 250 // You must be a writer to call this method! 251 // We can't check it - but otherwise it's your problem ... 252 // Thats why you don't need any mutex here. 253 254 #ifdef ENABLE_MUTEXDEBUG 255 // A writer is an exclusiv accessor! 256 LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::downgradeWriteAccess()", "No threadsafe code detected ... : Read count != 0!" ) 257 #endif 258 259 // Register himself as "new" reader. 260 // This value must be 0 before - because we support single writer access only! 261 ++m_nReadCount; 262 // Close barrier for other writer! 263 // Why? 264 // You hold the serializer mutex - next one can be a reader OR a writer. 265 // They must blocked then - because you will be a reader after this call 266 // and writer use this condition to wait for current reader! 267 m_aWriteCondition.reset(); 268 // Open door for next waiting thread in serialize queue! 269 m_aSerializer.release(); 270 } 271 272 //------------------------------------------------------------------------------------------------------------- 273 // private member 274 //------------------------------------------------------------------------------------------------------------- 275 private: 276 277 ::osl::Mutex m_aAccessLock ; /// regulate access on internal member of this instance 278 ::osl::Mutex m_aSerializer ; /// serialze incoming read/write access threads 279 ::osl::Condition m_aWriteCondition ; /// a writer must wait till current working reader are gone 280 sal_Int32 m_nReadCount ; /// every reader is registered - the last one open the door for waiting writer 281 282 }; // class FairRWLock 283 284 } // namespace framework 285 286 #endif // #ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_ 287