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