1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fairrwlock.hxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_
32 #define __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_
34 //_________________________________________________________________________________________________________________
36 //_________________________________________________________________________________________________________________
38 #include <threadhelp/inoncopyable.h>
39 #include <threadhelp/irwlock.h>
40 #include <macros/debug.hxx>
42 //_________________________________________________________________________________________________________________
44 //_________________________________________________________________________________________________________________
45 #include <com/sun/star/uno/XInterface.hpp>
46 #include <com/sun/star/lang/DisposedException.hpp>
48 //_________________________________________________________________________________________________________________
50 //_________________________________________________________________________________________________________________
51 #include <osl/mutex.hxx>
52 #include <osl/conditn.hxx>
54 //_________________________________________________________________________________________________________________
56 //_________________________________________________________________________________________________________________
60 //_________________________________________________________________________________________________________________
62 //_________________________________________________________________________________________________________________
64 //_________________________________________________________________________________________________________________
66 //_________________________________________________________________________________________________________________
68 /*-************************************************************************************************************//**
69 @short implement a read/write lock with fairness between read/write accessors
70 @descr These implementation never should used as base class! Use it as a member every time.
71 Use ReadGuard and/or WriteGuard in your methods (which work with these lock)
72 to make your code threadsafe.
73 Fair means: All reading or writing threads are synchronized AND serialzed by using one
74 mutex. For reader this mutex is used to access internal variables of this lock only;
75 for writer this mutex is used to have an exclusiv access on your class member!
76 => It's a multi-reader/single-writer lock, which no preferred accessor.
82 @devstatus ready to use
83 *//*-*************************************************************************************************************/
84 class FairRWLock
: public IRWLock
85 , private INonCopyable
87 //-------------------------------------------------------------------------------------------------------------
89 //-------------------------------------------------------------------------------------------------------------
92 /*-****************************************************************************************************//**
94 @descr Initialize instance with right start values for correct working.
95 no reader could exist => m_nReadCount = 0
96 don't block first comming writer => m_aWriteCondition.set()
104 *//*-*****************************************************************************************************/
108 m_aWriteCondition
.set();
111 inline virtual ~FairRWLock()
115 /*-****************************************************************************************************//**
117 @short set lock for reading
118 @descr A guard should call this method to acquire read access on your member.
119 Writing isn't allowed then - but nobody could check it for you!
121 @seealso method releaseReadAccess()
127 *//*-*****************************************************************************************************/
128 inline virtual void acquireReadAccess()
130 // Put call in "SERIALIZE"-queue!
131 // After successful acquiring this mutex we are alone ...
132 ::osl::MutexGuard
aSerializeGuard( m_aSerializer
);
134 // ... but we should synchronize us with other reader!
135 // May be - they will unregister himself by using releaseReadAccess()!
136 ::osl::MutexGuard
aAccessGuard( m_aAccessLock
);
138 // Now we must register us as reader by increasing counter.
139 // If this the first writer we must close door for possible writer.
140 // Other reader don't look for this barrier - they work parallel to us!
141 if( m_nReadCount
== 0 )
143 m_aWriteCondition
.reset();
148 /*-****************************************************************************************************//**
150 @short reset lock for reading
151 @descr A guard should call this method to release read access on your member.
153 @seealso method acquireReadAccess()
159 *//*-*****************************************************************************************************/
160 inline virtual void releaseReadAccess()
162 // The access lock is enough at this point
163 // because it's not allowed to wait for all reader or writer here!
164 // That will cause a deadlock!
165 ::osl::MutexGuard
aAccessGuard( m_aAccessLock
);
167 // Unregister as reader first!
168 // Open writer barrier then if it was the last reader.
170 if( m_nReadCount
== 0 )
172 m_aWriteCondition
.set();
176 /*-****************************************************************************************************//**
178 @short set lock for writing
179 @descr A guard should call this method to acquire write access on your member.
180 Reading is allowed too - of course.
181 After successfully calling of this method you are the only writer.
183 @seealso method releaseWriteAccess()
189 *//*-*****************************************************************************************************/
190 inline virtual void acquireWriteAccess()
192 // You have to stand in our serialize-queue till all reader
193 // are registered (not for releasing them!) or writer finished their work!
194 // Don't use a guard to do so - because you must hold the mutex till
195 // you call releaseWriteAccess()!
196 // After succesfull acquire you have to wait for current working reader.
197 // Used condition will open by last gone reader object.
198 m_aSerializer
.acquire();
199 m_aWriteCondition
.wait();
201 #ifdef ENABLE_MUTEXDEBUG
202 // A writer is an exclusiv accessor!
203 LOG_ASSERT2( m_nReadCount
!=0, "FairRWLock::acquireWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
207 /*-****************************************************************************************************//**
209 @short reset lock for writing
210 @descr A guard should call this method to release write access on your member.
212 @seealso method acquireWriteAccess()
218 *//*-*****************************************************************************************************/
219 inline virtual void releaseWriteAccess()
221 // The only one you have to do here is to release
222 // hold seriliaze-mutex. All other user of these instance are blocked
224 // You don't need any other mutex here - you are the only one in the moment!
226 #ifdef ENABLE_MUTEXDEBUG
227 // A writer is an exclusiv accessor!
228 LOG_ASSERT2( m_nReadCount
!=0, "FairRWLock::releaseWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
231 m_aSerializer
.release();
234 /*-****************************************************************************************************//**
236 @short downgrade a write access to a read access
237 @descr A guard should call this method to change a write to a read access.
238 New readers can work too - new writer are blocked!
240 @attention Don't call this method if you are not a writer!
241 Results are not defined then ...
242 An upgrade can't be implemented realy ... because acquiring new access
243 will be the same - there no differences!
251 *//*-*****************************************************************************************************/
252 inline virtual void downgradeWriteAccess()
254 // You must be a writer to call this method!
255 // We can't check it - but otherwise it's your problem ...
256 // Thats why you don't need any mutex here.
258 #ifdef ENABLE_MUTEXDEBUG
259 // A writer is an exclusiv accessor!
260 LOG_ASSERT2( m_nReadCount
!=0, "FairRWLock::downgradeWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
263 // Register himself as "new" reader.
264 // This value must be 0 before - because we support single writer access only!
266 // Close barrier for other writer!
268 // You hold the serializer mutex - next one can be a reader OR a writer.
269 // They must blocked then - because you will be a reader after this call
270 // and writer use this condition to wait for current reader!
271 m_aWriteCondition
.reset();
272 // Open door for next waiting thread in serialize queue!
273 m_aSerializer
.release();
276 //-------------------------------------------------------------------------------------------------------------
278 //-------------------------------------------------------------------------------------------------------------
281 ::osl::Mutex m_aAccessLock
; /// regulate access on internal member of this instance
282 ::osl::Mutex m_aSerializer
; /// serialze incoming read/write access threads
283 ::osl::Condition m_aWriteCondition
; /// a writer must wait till current working reader are gone
284 sal_Int32 m_nReadCount
; /// every reader is registered - the last one open the door for waiting writer
286 }; // class FairRWLock
288 } // namespace framework
290 #endif // #ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_