4 * Various thread synchronisation classes.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
30 * Revision 1.13 2004/03/22 10:15:27 rjongbloed
31 * Added classes similar to PWaitAndSignal to automatically unlock a PReadWriteMutex
32 * when goes out of scope.
34 * Revision 1.12 2002/12/11 03:21:28 robertj
35 * Updated documentation for read/write mutex.
37 * Revision 1.11 2002/10/04 08:20:44 robertj
38 * Changed read/write mutex so can be called by same thread without deadlock.
40 * Revision 1.10 2002/09/16 01:08:59 robertj
41 * Added #define so can select if #pragma interface/implementation is used on
42 * platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan.
44 * Revision 1.9 2002/05/01 03:45:31 robertj
45 * Added initialisation of PreadWriteMutex and changed slightly to agree
46 * with the text book definition of a semaphore for one of the mutexes.
48 * Revision 1.8 2002/04/30 06:21:54 robertj
49 * Fixed PReadWriteMutex class to implement text book algorithm!
51 * Revision 1.7 2001/05/22 12:49:32 robertj
52 * Did some seriously wierd rewrite of platform headers to eliminate the
53 * stupid GNU compiler warning about braces not matching.
55 * Revision 1.6 1999/03/09 02:59:51 robertj
56 * Changed comments to doc++ compatible documentation.
58 * Revision 1.5 1999/02/16 08:11:17 robertj
59 * MSVC 6.0 compatibility changes.
61 * Revision 1.4 1998/11/30 02:52:01 robertj
62 * New directory structure
64 * Revision 1.3 1998/10/31 12:46:45 robertj
65 * Renamed file for having general thread synchronisation objects.
66 * Added conditional mutex and read/write mutex thread synchronisation objects.
68 * Revision 1.2 1998/09/23 06:21:35 robertj
69 * Added open source copyright license.
71 * Revision 1.1 1998/05/30 13:26:15 robertj
77 #define _PSYNCPOINTACK
83 #include <ptlib/mutex.h>
84 #include <ptlib/syncpoint.h>
86 /** This class defines a thread synchonisation object.
88 This may be used to send signals to a thread and await an acknowldegement
89 that the signal was processed. This can be be used to initate an action in
90 another thread and wait for the action to be completed.
101 sync.Signal(); // At this point thread 1 wake up and does something.
102 do_yet_more(); // However, this does not get done until Acknowldege()
103 // is called in the other thread.
107 class PSyncPointAck
: public PSyncPoint
109 PCLASSINFO(PSyncPointAck
, PSyncPoint
);
112 /** If there are waiting (blocked) threads then unblock the first one that
113 was blocked. If no waiting threads and the count is less than the
114 maximum then increment the semaphore.
116 Unlike the PSyncPoint::Signal() this function will block until the
117 target thread that was blocked by the Wait() function has resumed
118 execution and called the Acknowledge() function.
120 The #waitTime# parameter is used as a maximum amount of time
121 to wait for the achnowledgement to be returned from the other thread.
123 virtual void Signal();
124 void Signal(const PTimeInterval
& waitTime
);
126 /** This indicates that the thread that was blocked in a Wait() on this
127 synchonrisation object has completed the operation the signal was
128 intended to initiate. This unblocks the thread that had called the
129 Signal() function to initiate the action.
138 /**This class defines a thread synchonisation object.
140 This is a special type of mutual exclusion, where a thread wishes to get
141 exlusive use of a resource but only if a certain other condition is met.
143 class PCondMutex
: public PMutex
145 PCLASSINFO(PCondMutex
, PMutex
);
148 /** This function attempts to acquire the mutex, but will block not only
149 until the mutex is free, but also that the condition returned by the
150 Condition() function is also met.
152 virtual void WaitCondition();
154 /** If there are waiting (blocked) threads then unblock the first one that
155 was blocked. If no waiting threads and the count is less than the
156 maximum then increment the semaphore.
158 virtual void Signal();
160 /** This is the condition that must be met for the WaitCondition() function
161 to acquire the mutex.
163 virtual BOOL
Condition() = 0;
165 /** This function is called immediately before blocking on the condition in
166 the WaitCondition() function. This could get called multiple times
167 before the condition is met and the WaitCondition() function returns.
169 virtual void OnWait();
172 PSyncPoint syncPoint
;
176 /** This is a PCondMutex for which the conditional is the value of an integer.
178 class PIntCondMutex
: public PCondMutex
180 PCLASSINFO(PIntCondMutex
, PCondMutex
);
183 /**@name Construction */
185 /// defines possible operators on current value and target value
189 /// Less than or equal to
193 /// Greater than or equal to
200 Create a cond mutex using an integer
203 int value
= 0, /// initial value if the integer
204 int target
= 0, /// target vaue which causes the mutex to unlock
205 Operation operation
= LE
/// comparison operator
209 /**@name Overrides from class PObject */
211 /** Print the object on the stream. This will be of the form
212 #"(value < target)"#.
214 void PrintOn(ostream
& strm
) const;
217 /**@name Condition access functions */
219 /** This is the condition that must be met for the WaitCondition() function
220 to acquire the mutex.
222 @return TRUE if condition is met.
224 virtual BOOL
Condition();
226 /**Get the current value of the condition variable.
227 @return Current condition variable value.
229 operator int() const { return value
; }
231 /**Assign new condition value.
232 Use the Wait() function to acquire the mutex, modify the value, then
233 release the mutex, possibly releasing the thread in the WaitCondition()
234 function if the condition was met by the operation.
236 @return The object reference for consecutive operations in the same statement.
238 PIntCondMutex
& operator=(int newval
);
240 /**Increment condition value.
241 Use the Wait() function to acquire the mutex, modify the value, then
242 release the mutex, possibly releasing the thread in the WaitCondition()
243 function if the condition was met by the operation.
245 @return The object reference for consecutive operations in the same statement.
247 PIntCondMutex
& operator++();
249 /**Add to condition value.
250 Use the Wait() function to acquire the mutex, modify the value, then
251 release the mutex, possibly releasing the thread in the WaitCondition()
252 function if the condition was met by the operation.
254 @return The object reference for consecutive operations in the same statement.
256 PIntCondMutex
& operator+=(int inc
);
258 /**Decrement condition value.
259 Use the Wait() function to acquire the mutex, modify the value, then
260 release the mutex, possibly releasing the thread in the WaitCondition()
261 function if the condition was met by the operation.
263 @return The object reference for consecutive operations in the same statement.
265 PIntCondMutex
& operator--();
267 /**Subtract from condition value.
268 Use the Wait() function to acquire the mutex, modify the value, then
269 release the mutex, possibly releasing the thread in the WaitCondition()
270 function if the condition was met by the operation.
272 @return The object reference for consecutive operations in the same statement.
274 PIntCondMutex
& operator-=(int dec
);
284 /** This class defines a thread synchonisation object.
286 This is a special type of mutual exclusion, where the excluded area may
287 have multiple read threads but only one write thread and the read threads
288 are blocked on write as well.
291 class PReadWriteMutex
: public PObject
293 PCLASSINFO(PReadWriteMutex
, PObject
);
295 /**@name Construction */
300 /**@name Operations */
302 /** This function attempts to acquire the mutex for reading.
303 This call may be nested and must have an equal number of EndRead()
304 calls for the mutex to be released.
308 /** This function attempts to release the mutex for reading.
312 /** This function attempts to acquire the mutex for writing.
313 This call may be nested and must have an equal number of EndWrite()
314 calls for the mutex to be released.
316 Note, if the same thread had a read lock previous to this call then
317 the read lock is automatically released and reacquired when EndWrite()
318 is called, unless an EndRead() is called. The EndRead() and EndWrite()
319 calls do not have to be strictly nested.
321 It should also be noted that a consequence of this is that another
322 thread may acquire the write lock before the thread that previously
323 had the read lock. Thus it is impossibly to go straight from a read
324 lock to write lock without the possiblility of the object being
325 changed and application logic should take this into account.
329 /** This function attempts to release the mutex for writing.
330 Note, if the same thread had a read lock when the StartWrite() was
331 called which has not yet been released by an EndRead() call then this
332 will reacquire the read lock.
334 It should also be noted that a consequence of this is that another
335 thread may acquire the write lock before the thread that regains the
336 read lock. Thus it is impossibly to go straight from a write lock to
337 read lock without the possiblility of the object being changed and
338 application logic should take this into account.
344 PSemaphore readerSemaphore
;
346 unsigned readerCount
;
347 PMutex starvationPreventer
;
349 PSemaphore writerSemaphore
;
351 unsigned writerCount
;
353 class Nest
: public PObject
355 PCLASSINFO(Nest
, PObject
);
356 Nest() { readerCount
= writerCount
= 0; }
357 unsigned readerCount
;
358 unsigned writerCount
;
360 PDictionary
<POrdinalKey
, Nest
> nestedThreads
;
363 Nest
* GetNest() const;
366 void InternalStartRead();
367 void InternalEndRead();
371 /**This class starts a read operation for the PReadWriteMutex on construction
372 and automatically ends the read operation on destruction.
374 This is very usefull for constructs such as:
378 PReadWaitAndSignal mutexWait(myMutex);
388 class PReadWaitAndSignal
{
390 /**Create the PReadWaitAndSignal wait instance.
391 This will wait on the specified PReadWriteMutex using the #StartRead()#
392 function before returning.
395 const PReadWriteMutex
& rw
, /// PReadWriteMutex descendent to wait/signal.
396 BOOL start
= TRUE
/// Start read operation on PReadWriteMutex before returning.
398 /** End read operation on the PReadWriteMutex.
399 This will execute the EndRead() function on the PReadWriteMutex that
400 was used in the construction of this instance.
402 ~PReadWaitAndSignal();
405 PReadWriteMutex
& mutex
;
409 /**This class starts a write operation for the PReadWriteMutex on construction
410 and automatically ends the write operation on destruction.
412 This is very usefull for constructs such as:
416 PWriteWaitAndSignal mutexWait(myMutex);
426 class PWriteWaitAndSignal
{
428 /**Create the PWriteWaitAndSignal wait instance.
429 This will wait on the specified PReadWriteMutex using the #StartWrite()#
430 function before returning.
433 const PReadWriteMutex
& rw
, /// PReadWriteMutex descendent to wait/signal.
434 BOOL start
= TRUE
/// Start write operation on PReadWriteMutex before returning.
436 /** End write operation on the PReadWriteMutex.
437 This will execute the EndWrite() function on the PReadWriteMutex that
438 was used in the construction of this instance.
440 ~PWriteWaitAndSignal();
443 PReadWriteMutex
& mutex
;
447 // End Of File ///////////////////////////////////////////////////////////////