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