1 /*
2 * safecoll.h
3 *
4 * Thread safe collection classes.
5 *
6 * Portable Windows Library
7 *
8 * Copyright (c) 2002 Equivalence Pty. Ltd.
9 *
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/
14 *
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
18 * under the License.
19 *
20 * The Original Code is Portable Windows Library.
21 *
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Revision: 27948 $
27 * $Author: rjongbloed $
28 * $Date: 2012-06-30 22:54:23 -0500 (Sat, 30 Jun 2012) $
29 */
30
31 #ifndef PTLIB_SAFE_COLLECTION_H
32 #define PTLIB_SAFE_COLLECTION_H
33
34 #ifdef P_USE_PRAGMA
35 #pragma interface
36 #endif
37
38
39 /** This class defines a thread-safe object in a collection.
40
41 This is part of a set of classes to solve the general problem of a
42 collection (eg a PList or PDictionary) of objects that needs to be a made
43 thread safe. Any thread can add, read, write or remove an object with both
44 the object and the database of objects itself kept thread safe.
45
46 The act of adding a new object is simple and only requires locking the
47 collection itself during the add.
48
49 Locating an object is more complicated. The obvious lock on the collection
50 is made for the initial search. But we wish to have the full collection lock
51 for as short a period as possible (for performance reasons) so we lock the
52 individual object and release the lock on the collection.
53
54 A simple mutex on the object however is very dangerous as it can be (and
55 should be able to be!) locked from other threads independently of the
56 collection. If one of these threads subsequently needs to get at the
57 collection (eg it wants to remove the object) then we will have a deadlock.
58 Also, to avoid a race condition with the object begin deleted, the objects
59 lock must be made while the collection lock is set. The performance gains
60 are then lost as if something has the object locked for a long time, then
61 another object wanting that object will actually lock the collection for a
62 long time as well.
63
64 So, an object has 4 states: unused, referenced, reading & writing. With the
65 additional rider of "being removed". This flag prevents new locks from being
66 acquired and waits for all locks to be relinquished before removing the
67 object from the system. This prevents numerous race conditions and accesses
68 to deleted objects.
69
70 The "unused" state indicates the object exists in the collection but no
71 threads anywhere is using it. It may be moved to any state by any thread
72 while in this state. An object cannot be deleted (ie memory deallocated)
73 until it is unused.
74
75 The "referenced" state indicates that a thread has a reference (eg pointer)
76 to the object and it should not be deleted. It may be locked for reading or
77 writing at any time thereafter.
78
79 The "reading" state is a form of lock that indicates that a thread is
80 reading from the object but not writing. Multiple threads can obtain a read
81 lock. Note the read lock has an implicit "reference" state in it.
82
83 The "writing" state is a form of lock where the data in the object may
84 be changed. It can only be obtained exclusively and if there are no read
85 locks present. Again there is an implicit reference state in this lock.
86
87 Note that threads going to the "referenced" state may do so regardless of
88 the read or write locks present.
89
90 Access to safe objects (especially when in a safe collection) is recommended
91 to by the PSafePtr<> class which will manage reference counting and the
92 automatic unlocking of objects ones the pointer goes out of scope. It may
93 also be used to lock each object of a collection in turn.
94
95 The enumeration of a PSafeCollection of PSafeObjects utilises the PSafePtr
96 class in a classic "for loop" manner.
97
98 <CODE>
99 for (PSafePtr<MyClass> iter(collection, PSafeReadWrite); iter != NULL; ++iter)
100 iter->Process();
101 </CODE>
102
103 There is one piece if important behaviour in the above. If while enumerating
104 a specic object in the collection, that object is "safely deleted", you are
105 guaranteed that the object is still usable and has not been phsyically
106 deleted, however it will no longer be in the collection, so the enumeration
107 will stop as it can no longer determine where in the collection it was.
108
109 What to do in this case is to take a "snapshot" at a point of time that can be safely and completely
110 iterated over:
111
112 <CODE>
113 PSafeList<MyClass> collCopy = collection;
114 for (PSafePtr<MyClass> iter(callCopy, PSafeReadWrite); iter != NULL; ++iter)
115 iter->Process();
116 </CODE>
117
118 */
119 class PSafeObject : public PObject
120 {
121 PCLASSINFO(PSafeObject, PObject);
122 public:
123 /**@name Construction */
124 //@{
125 /**Create a thread safe object.
126 */
127 PSafeObject(
128 PSafeObject * indirectLock = NULL ///< Other safe object to be locked when this is locked
129 );
130 //@}
131
132 /**@name Operations */
133 //@{
134 /**Increment the reference count for object.
135 This will guarantee that the object is not deleted (ie memory
136 deallocated) as the caller thread is using the object, but not
137 necessarily at this time locking it.
138
139 If the function returns false, then the object has been flagged for
140 deletion and the calling thread should immediately cease using the
141 object.
142
143 A typical use of this would be when an entity (eg a thread) has a
144 pointer to the object but is not currenty accessing the objects data.
145 The LockXXX functions may be called independetly of the reference
146 system and the pointer beiong used for the LockXXX call is guaranteed
147 to be usable.
148
149 It is recommended that the PSafePtr<> class is used to manage this
150 rather than the application calling this function directly.
151 */
152 PBoolean SafeReference();
153
154 /**Decrement the reference count for object.
155 This indicates that the thread no longer has anything to do with the
156 object and it may be deleted (ie memory deallocated).
157
158 It is recommended that the PSafePtr<> class is used to manage this
159 rather than the application calling this function directly.
160
161 @return true if reference count has reached zero and is not being
162 safely deleted elsewhere ie SafeRemove() not called
163 */
164 PBoolean SafeDereference();
165
166 /**Lock the object for Read Only access.
167 This will lock the object in read only mode. Multiple threads may lock
168 the object read only, but only one thread can lock for read/write.
169 Also, no read only threads can be present for the read/write lock to
170 occur and no read/write lock can be present for any read only locks to
171 occur.
172
173 If the function returns false, then the object has been flagged for
174 deletion and the calling thread should immediately cease use of the
175 object, possibly executing the SafeDereference() function to remove
176 any references it may have acquired.
177
178 It is expected that the caller had already called the SafeReference()
179 function (directly or implicitly) before calling this function. It is
180 recommended that the PSafePtr<> class is used to automatically manage
181 the reference counting and locking of objects.
182 */
183 PBoolean LockReadOnly() const;
184
185 /**Release the read only lock on an object.
186 Unlock the read only mutex that a thread had obtained. Multiple threads
187 may lock the object read only, but only one thread can lock for
188 read/write. Also, no read only threads can be present for the
189 read/write lock to occur and no read/write lock can be present for any
190 read only locks to occur.
191
192 It is recommended that the PSafePtr<> class is used to automatically
193 manage the reference counting and unlocking of objects.
194 */
195 void UnlockReadOnly() const;
196
197 /**Lock the object for Read/Write access.
198 This will lock the object in read/write mode. Multiple threads may lock
199 the object read only, but only one thread can lock for read/write.
200 Also no read only threads can be present for the read/write lock to
201 occur and no read/write lock can be present for any read only locks to
202 occur.
203
204 If the function returns false, then the object has been flagged for
205 deletion and the calling thread should immediately cease use of the
206 object, possibly executing the SafeDereference() function to remove
207 any references it may have acquired.
208
209 It is expected that the caller had already called the SafeReference()
210 function (directly or implicitly) before calling this function. It is
211 recommended that the PSafePtr<> class is used to automatically manage
212 the reference counting and locking of objects.
213 */
214 PBoolean LockReadWrite();
215
216 /**Release the read/write lock on an object.
217 Unlock the read/write mutex that a thread had obtained. Multiple threads
218 may lock the object read only, but only one thread can lock for
219 read/write. Also, no read only threads can be present for the
220 read/write lock to occur and no read/write lock can be present for any
221 read only locks to occur.
222
223 It is recommended that the PSafePtr<> class is used to automatically
224 manage the reference counting and unlocking of objects.
225 */
226 void UnlockReadWrite();
227
228 /**Set the removed flag.
229 This flags the object as beeing removed but does not physically delete
230 the memory being used by it. The SafelyCanBeDeleted() can then be used
231 to determine when all references to the object have been released so it
232 may be safely deleted.
233
234 This is typically used by the PSafeCollection class and is not expected
235 to be used directly by an application.
236 */
237 void SafeRemove();
238
239 /**Determine if the object can be safely deleted.
240 This determines if the object has been flagged for deletion and all
241 references to it have been released.
242
243 This is typically used by the PSafeCollection class and is not expected
244 to be used directly by an application.
245 */
246 PBoolean SafelyCanBeDeleted() const;
247
248 /**Do any garbage collection that may be required by the object so that it
249 may be finally deleted. This is especially useful if there a references
250 back to this object which this object is in charge of disposing of. This
251 reference "glare" is to be resolved by this function being called every
252 time the owner collection is cleaning up, causing a cascade of clean ups
253 that might need to be required.
254
255 Default implementation simply returns true.
256
257 @return true if object may be deleted.
258 */
259 virtual bool GarbageCollection();
260 //@}
261
262 private:
263 mutable PMutex safetyMutex;
264 unsigned safeReferenceCount;
265 bool safelyBeingRemoved;
266 PReadWriteMutex safeInUseMutex;
267 PReadWriteMutex * safeInUse;
268
269 friend class PSafeCollection;
270 };
271
272
273 /**Lock a PSafeObject for read only and automatically unlock it when go out of scope.
274 */
275 class PSafeLockReadOnly
276 {
277 public:
278 PSafeLockReadOnly(const PSafeObject & object);
279 ~PSafeLockReadOnly();
280 PBoolean Lock();
281 void Unlock();
IsLocked()282 PBoolean IsLocked() const { return locked; }
283 bool operator!() const { return !locked; }
284
285 protected:
286 PSafeObject & safeObject;
287 PBoolean locked;
288 };
289
290
291
292 /**Lock a PSafeObject for read/write and automatically unlock it when go out of scope.
293 */
294 class PSafeLockReadWrite
295 {
296 public:
297 PSafeLockReadWrite(const PSafeObject & object);
298 ~PSafeLockReadWrite();
299 PBoolean Lock();
300 void Unlock();
IsLocked()301 PBoolean IsLocked() const { return locked; }
302 bool operator!() const { return !locked; }
303
304 protected:
305 PSafeObject & safeObject;
306 PBoolean locked;
307 };
308
309
310
311 /** This class defines a thread-safe collection of objects.
312 This class is a wrapper around a standard PCollection class which allows
313 only safe, mutexed, access to the collection.
314
315 This is part of a set of classes to solve the general problem of a
316 collection (eg a PList or PDictionary) of objects that needs to be a made
317 thread safe. Any thread can add, read, write or remove an object with both
318 the object and the database of objects itself kept thread safe.
319
320 See the PSafeObject class for more details. Especially in regard to
321 enumeration of collections.
322 */
323 class PSafeCollection : public PObject
324 {
325 PCLASSINFO(PSafeCollection, PObject);
326 public:
327 /**@name Construction */
328 //@{
329 /**Create a thread safe collection of objects.
330 Note the collection is automatically deleted on destruction.
331 */
332 PSafeCollection(
333 PCollection * collection ///< Actual collection of objects
334 );
335
336 /**Destroy the thread safe collection.
337 The will delete the collection object provided in the constructor.
338 */
339 ~PSafeCollection();
340 //@}
341
342 /**@name Operations */
343 //@{
344 protected:
345 /**Remove an object to the collection.
346 This function removes the object from the collection itself, but does
347 not actually delete the object. It simply moves the object to a list
348 of objects to be garbage collected at a later time.
349
350 As for Append() full mutual exclusion locking on the collection itself
351 is maintained.
352 */
353 virtual PBoolean SafeRemove(
354 PSafeObject * obj ///< Object to remove from collection
355 );
356
357 /**Remove an object to the collection.
358 This function removes the object from the collection itself, but does
359 not actually delete the object. It simply moves the object to a list
360 of objects to be garbage collected at a later time.
361
362 As for Append() full mutual exclusion locking on the collection itself
363 is maintained.
364 */
365 virtual PBoolean SafeRemoveAt(
366 PINDEX idx ///< Object index to remove
367 );
368
369 public:
370 /**Remove all objects in collection.
371 */
372 virtual void RemoveAll(
373 PBoolean synchronous = false ///< Wait till objects are deleted before returning
374 );
375
376 /**Disallow the automatic delete any objects that have been removed.
377 Objects are simply removed from the collection and not marked for
378 deletion using PSafeObject::SafeRemove() and DeleteObject().
379 */
380 void AllowDeleteObjects(
381 PBoolean yes = true ///< New value for flag for deleting objects
382 ) { deleteObjects = yes; }
383
384 /**Disallow the automatic delete any objects that have been removed.
385 Objects are simply removed from the collection and not marked for
386 deletion using PSafeObject::SafeRemove() and DeleteObject().
387 */
DisallowDeleteObjects()388 void DisallowDeleteObjects() { deleteObjects = false; }
389
390 /**Delete any objects that have been removed.
391 Returns true if all objects in the collection have been removed and
392 their pending deletions carried out.
393 */
394 virtual PBoolean DeleteObjectsToBeRemoved();
395
396 /**Delete an objects that has been removed.
397 */
398 virtual void DeleteObject(PObject * object) const;
399
400 /**Start a timer to automatically call DeleteObjectsToBeRemoved().
401 */
402 virtual void SetAutoDeleteObjects();
403
404 /**Get the current size of the collection.
405 Note that usefulness of this function is limited as it is merely an
406 instantaneous snapshot of the state of the collection.
407 */
408 PINDEX GetSize() const;
409
410 /**Determine if the collection is empty.
411 Note that usefulness of this function is limited as it is merely an
412 instantaneous snapshot of the state of the collection.
413 */
IsEmpty()414 PBoolean IsEmpty() const { return GetSize() == 0; }
415
416 /**Get the mutex for the collection.
417 */
GetMutex()418 const PMutex & GetMutex() const { return collectionMutex; }
419 //@}
420
421 protected:
422 void CopySafeCollection(PCollection * other);
423 void CopySafeDictionary(PAbstractDictionary * other);
424 void SafeRemoveObject(PSafeObject * obj);
425 PDECLARE_NOTIFIER(PTimer, PSafeCollection, DeleteObjectsTimeout);
426
427 PCollection * collection;
428 mutable PMutex collectionMutex;
429 bool deleteObjects;
430 PList<PSafeObject> toBeRemoved;
431 PMutex removalMutex;
432 PTimer deleteObjectsTimer;
433
434 private:
PSafeCollection(const PSafeCollection & other)435 PSafeCollection(const PSafeCollection & other) : PObject(other) { }
436 void operator=(const PSafeCollection &) { }
437
438 friend class PSafePtrBase;
439 };
440
441
442 enum PSafetyMode {
443 PSafeReference,
444 PSafeReadOnly,
445 PSafeReadWrite
446 };
447
448 /** This class defines a base class for thread-safe pointer to an object.
449
450 This is part of a set of classes to solve the general problem of a
451 collection (eg a PList or PDictionary) of objects that needs to be a made
452 thread safe. Any thread can add, read, write or remove an object with both
453 the object and the database of objects itself kept thread safe.
454
455 NOTE: the PSafePtr will allow safe and mutexed access to objects but is not
456 thread safe itself! You should not share PSafePtr instances across threads.
457
458 See the PSafeObject class for more details.
459 */
460 class PSafePtrBase : public PObject
461 {
462 PCLASSINFO(PSafePtrBase, PObject);
463
464 /**@name Construction */
465 //@{
466 protected:
467 /**Create a new pointer to a PSafeObject.
468 An optional locking mode may be provided to lock the object for reading
469 or writing and automatically unlock it on destruction.
470
471 Note that this version is not associated with a collection so the ++
472 and -- operators will not work.
473 */
474 PSafePtrBase(
475 PSafeObject * obj = NULL, ///< Physical object to point to.
476 PSafetyMode mode = PSafeReference ///< Locking mode for the object
477 );
478
479 /**Create a new pointer to a PSafeObject.
480 An optional locking mode may be provided to lock the object for reading
481 or writing and automatically unlock it on destruction.
482
483 The idx'th entry of the collection is pointed to by this object. If the
484 idx is beyond the size of the collection, the pointer is NULL.
485 */
486 PSafePtrBase(
487 const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
488 PSafetyMode mode, ///< Locking mode for the object
489 PINDEX idx ///< Index into collection to point to
490 );
491
492 /**Create a new pointer to a PSafeObject.
493 An optional locking mode may be provided to lock the object for reading
494 or writing and automatically unlock it on destruction.
495
496 The obj parameter is only set if it contained in the collection,
497 otherwise the pointer is NULL.
498 */
499 PSafePtrBase(
500 const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
501 PSafetyMode mode, ///< Locking mode for the object
502 PSafeObject * obj ///< Inital object in collection to point to
503 );
504
505 /**Copy the pointer to the PSafeObject.
506 This will create a copy of the pointer with the same locking mode and
507 lock on the PSafeObject. It will also increment the reference count on
508 the PSafeObject as well.
509 */
510 PSafePtrBase(
511 const PSafePtrBase & enumerator ///< Pointer to copy
512 );
513
514 public:
515 /**Unlock and dereference the PSafeObject this is pointing to.
516 */
517 ~PSafePtrBase();
518 //@}
519
520 /**@name Overrides from class PObject */
521 //@{
522 /**Compare the pointers.
523 Note this is not a value comparison and will only return EqualTo if the
524 two PSafePtrBase instances are pointing to the same instance.
525 */
526 virtual Comparison Compare(
527 const PObject & obj ///< Other instance to compare against
528 ) const;
529
530 /** Output the contents of the object to the stream. The exact output is
531 dependent on the exact semantics of the descendent class. This is
532 primarily used by the standard <code>#operator<<</code> function.
533
534 The default behaviour is to print the class name.
535 */
536 virtual void PrintOn(
537 ostream &strm // Stream to print the object into.
538 ) const;
539 //@}
540
541 /**@name Operations */
542 //@{
543 /**Set the pointer to NULL, unlocking/dereferencing existing pointer value.
544 */
545 virtual void SetNULL();
546
547 /**Return true if pointer is NULL.
548 */
549 bool operator!() const { return currentObject == NULL; }
550
551 /**Get the locking mode used by this pointer.
552 */
GetSafetyMode()553 PSafetyMode GetSafetyMode() const { return lockMode; }
554
555 /**Change the locking mode used by this pointer.
556
557 If the function returns false, then the object has been flagged for
558 deletion and the calling thread should immediately cease use of the
559 object. This instance pointer will be set to NULL.
560 */
561 virtual PBoolean SetSafetyMode(
562 PSafetyMode mode ///< New locking mode
563 );
564
565 /**Get the associated collection this pointer may be contained in.
566 */
GetCollection()567 const PSafeCollection * GetCollection() const { return collection; }
568 //@}
569
570 virtual void Assign(const PSafePtrBase & ptr);
571 virtual void Assign(const PSafeCollection & safeCollection);
572 virtual void Assign(PSafeObject * obj);
573 virtual void Assign(PINDEX idx);
574
575 protected:
576 virtual void Next();
577 virtual void Previous();
578 virtual void DeleteObject(PSafeObject * obj);
579
580 enum EnterSafetyModeOption {
581 WithReference,
582 AlreadyReferenced
583 };
584 PBoolean EnterSafetyMode(EnterSafetyModeOption ref);
585
586 enum ExitSafetyModeOption {
587 WithDereference,
588 NoDereference
589 };
590 void ExitSafetyMode(ExitSafetyModeOption ref);
591
LockPtr()592 virtual void LockPtr() { }
UnlockPtr()593 virtual void UnlockPtr() { }
594
595 protected:
596 const PSafeCollection * collection;
597 PSafeObject * currentObject;
598 PSafetyMode lockMode;
599 };
600
601
602 /** This class defines a base class for thread-safe pointer to an object.
603
604 This is part of a set of classes to solve the general problem of a
605 collection (eg a PList or PDictionary) of objects that needs to be a made
606 thread safe. Any thread can add, read, write or remove an object with both
607 the object and the database of objects itself kept thread safe.
608
609 NOTE: unlikel PSafePtrBase, pointers based on this class are thread safe
610 themseleves, at the expense of performance on every operation.
611
612 See the PSafeObject class for more details.
613 */
614 class PSafePtrMultiThreaded : public PSafePtrBase
615 {
616 PCLASSINFO(PSafePtrMultiThreaded, PSafePtrBase);
617
618 /**@name Construction */
619 //@{
620 protected:
621 /**Create a new pointer to a PSafeObject.
622 An optional locking mode may be provided to lock the object for reading
623 or writing and automatically unlock it on destruction.
624
625 Note that this version is not associated with a collection so the ++
626 and -- operators will not work.
627 */
628 PSafePtrMultiThreaded(
629 PSafeObject * obj = NULL, ///< Physical object to point to.
630 PSafetyMode mode = PSafeReference ///< Locking mode for the object
631 );
632
633 /**Create a new pointer to a PSafeObject.
634 An optional locking mode may be provided to lock the object for reading
635 or writing and automatically unlock it on destruction.
636
637 The idx'th entry of the collection is pointed to by this object. If the
638 idx is beyond the size of the collection, the pointer is NULL.
639 */
640 PSafePtrMultiThreaded(
641 const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
642 PSafetyMode mode, ///< Locking mode for the object
643 PINDEX idx ///< Index into collection to point to
644 );
645
646 /**Create a new pointer to a PSafeObject.
647 An optional locking mode may be provided to lock the object for reading
648 or writing and automatically unlock it on destruction.
649
650 The obj parameter is only set if it contained in the collection,
651 otherwise the pointer is NULL.
652 */
653 PSafePtrMultiThreaded(
654 const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
655 PSafetyMode mode, ///< Locking mode for the object
656 PSafeObject * obj ///< Inital object in collection to point to
657 );
658
659 /**Copy the pointer to the PSafeObject.
660 This will create a copy of the pointer with the same locking mode and
661 lock on the PSafeObject. It will also increment the reference count on
662 the PSafeObject as well.
663 */
664 PSafePtrMultiThreaded(
665 const PSafePtrMultiThreaded & enumerator ///< Pointer to copy
666 );
667
668 public:
669 /**Unlock and dereference the PSafeObject this is pointing to.
670 */
671 ~PSafePtrMultiThreaded();
672 //@}
673
674 /**@name Overrides from class PObject */
675 //@{
676 /**Compare the pointers.
677 Note this is not a value comparison and will only return EqualTo if the
678 two PSafePtrBase instances are pointing to the same instance.
679 */
680 virtual Comparison Compare(
681 const PObject & obj ///< Other instance to compare against
682 ) const;
683 //@}
684
685 /**@name Operations */
686 //@{
687 /**Set the pointer to NULL, unlocking/dereferencing existing pointer value.
688 */
689 virtual void SetNULL();
690
691 /**Change the locking mode used by this pointer.
692
693 If the function returns false, then the object has been flagged for
694 deletion and the calling thread should immediately cease use of the
695 object. This instance pointer will be set to NULL.
696 */
697 virtual PBoolean SetSafetyMode(
698 PSafetyMode mode ///< New locking mode
699 );
700 //@}
701
702 virtual void Assign(const PSafePtrMultiThreaded & ptr);
703 virtual void Assign(const PSafePtrBase & ptr);
704 virtual void Assign(const PSafeCollection & safeCollection);
705 virtual void Assign(PSafeObject * obj);
706 virtual void Assign(PINDEX idx);
707
708 protected:
709 virtual void Next();
710 virtual void Previous();
711 virtual void DeleteObject(PSafeObject * obj);
712
LockPtr()713 virtual void LockPtr() { m_mutex.Wait(); }
714 virtual void UnlockPtr();
715
716 protected:
717 mutable PMutex m_mutex;
718 PSafeObject * m_objectToDelete;
719 };
720
721
722 /** This class defines a thread-safe enumeration of object in a collection.
723
724 This is part of a set of classes to solve the general problem of a
725 collection (eg a PList or PDictionary) of objects that needs to be a made
726 thread safe. Any thread can add, read, write or remove an object with both
727 the object and the database of objects itself kept thread safe.
728
729 There are two modes of safe pointer: one that is enumerating a collection;
730 and one that is independent of the collection that the safe object is in.
731 There are subtle semantics that must be observed in each of these two
732 modes especially when switching from one to the other.
733
734 NOTE: the PSafePtr will allow safe and mutexed access to objects but may not
735 be thread safe itself! This depends on the base class being used. If the more
736 efficient PSafePtrBase class is used you should not share PSafePtr instances
737 across threads.
738
739 See the PSafeObject class for more details, especially in regards to
740 enumeration of collections.
741 */
742 template <class T, class BaseClass = PSafePtrBase> class PSafePtr : public BaseClass
743 {
744 public:
745 /**@name Construction */
746 //@{
747 /**Create a new pointer to a PSafeObject.
748 An optional locking mode may be provided to lock the object for reading
749 or writing and automatically unlock it on destruction.
750
751 Note that this version is not associated with a collection so the ++
752 and -- operators will not work.
753 */
754 PSafePtr(
755 T * obj = NULL, ///< Physical object to point to.
756 PSafetyMode mode = PSafeReference ///< Locking mode for the object
BaseClass(obj,mode)757 ) : BaseClass(obj, mode) { }
758
759 /**Create a new pointer to a PSafeObject.
760 An optional locking mode may be provided to lock the object for reading
761 or writing and automatically unlock it on destruction.
762
763 The idx'th entry of the collection is pointed to by this object. If the
764 idx is beyond the size of the collection, the pointer is NULL.
765 */
766 PSafePtr(
767 const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
768 PSafetyMode mode = PSafeReadWrite, ///< Locking mode for the object
769 PINDEX idx = 0 ///< Index into collection to point to
BaseClass(safeCollection,mode,idx)770 ) : BaseClass(safeCollection, mode, idx) { }
771
772 /**Create a new pointer to a PSafeObject.
773 An optional locking mode may be provided to lock the object for reading
774 or writing and automatically unlock it on destruction.
775
776 The obj parameter is only set if it contained in the collection,
777 otherwise the pointer is NULL.
778 */
PSafePtr(const PSafeCollection & safeCollection,PSafetyMode mode,PSafeObject * obj)779 PSafePtr(
780 const PSafeCollection & safeCollection, ///< Collection pointer will enumerate
781 PSafetyMode mode, ///< Locking mode for the object
782 PSafeObject * obj ///< Inital object in collection to point to
783 ) : BaseClass(safeCollection, mode, obj) { }
784
785 /**Copy the pointer to the PSafeObject.
786 This will create a copy of the pointer with the same locking mode and
787 lock on the PSafeObject. It will also increment the reference count on
788 the PSafeObject as well.
789 */
PSafePtr(const PSafePtr & ptr)790 PSafePtr(
791 const PSafePtr & ptr ///< Pointer to copy
792 ) : BaseClass(ptr) { }
793
794 /**Copy the pointer to the PSafeObject.
795 This will create a copy of the pointer with the same locking mode and
796 lock on the PSafeObject. It will also increment the reference count on
797 the PSafeObject as well.
798 */
799 PSafePtr & operator=(const PSafePtr & ptr)
800 {
801 BaseClass::Assign(ptr);
802 return *this;
803 }
804
805 /**Start an enumerated PSafeObject.
806 This will create a read/write locked reference to teh first element in
807 the collection.
808 */
809 PSafePtr & operator=(const PSafeCollection & safeCollection)
810 {
811 BaseClass::Assign(safeCollection);
812 return *this;
813 }
814
815 /**Set the new pointer to a PSafeObject.
816 This will set the pointer to the new object. The old object pointed to
817 will be unlocked and dereferenced and the new object referenced.
818
819 If the safe pointer has an associated collection and the new object is
820 in that collection, then the object is set to the same locking mode as
821 the previous pointer value. This, in effect, jumps the enumeration of a
822 collection to the specifed object.
823
824 If the safe pointer has no associated collection or the object is not
825 in the associated collection, then the object is always only referenced
826 and there is no read only or read/write lock done. In addition any
827 associated collection is removed so this becomes a non enumerating
828 safe pointer.
829 */
830 PSafePtr & operator=(T * obj)
831 {
832 this->Assign(obj);
833 return *this;
834 }
835
836 /**Set the new pointer to a collection index.
837 This will set the pointer to the new object to the index entry in the
838 colelction that the pointer was created with. The old object pointed to
839 will be unlocked and dereferenced and the new object referenced and set
840 to the same locking mode as the previous pointer value.
841
842 If the idx'th object is not in the collection, then the safe pointer
843 is set to NULL.
844 */
845 PSafePtr & operator=(PINDEX idx)
846 {
847 BaseClass::Assign(idx);
848 return *this;
849 }
850
851 /**Set the safe pointer to the specified object.
852 This will return a PSafePtr for the previous value of this. It does
853 this in a thread safe manner so "test and set" semantics are obeyed.
854 */
Set(T * obj)855 PSafePtr Set(T * obj)
856 {
857 this->LockPtr();
858 PSafePtr oldPtr = *this;
859 this->Assign(obj);
860 this->UnlockPtr();
861 return oldPtr;
862 }
863 //@}
864
865 /**@name Operations */
866 //@{
867 /**Return the physical pointer to the object.
868 */
869 operator T*() const { return (T *)BaseClass::currentObject; }
870
871 /**Return the physical pointer to the object.
872 */
873 T & operator*() const { return *(T *)PAssertNULL(BaseClass::currentObject); }
874
875 /**Allow access to the physical object the pointer is pointing to.
876 */
877 T * operator->() const { return (T *)PAssertNULL(BaseClass::currentObject); }
878
879 /**Post-increment the pointer.
880 This requires that the pointer has been created with a PSafeCollection
881 object so that it can enumerate the collection.
882 */
883 T * operator++(int)
884 {
885 T * previous = (T *)BaseClass::currentObject;
886 BaseClass::Next();
887 return previous;
888 }
889
890 /**Pre-increment the pointer.
891 This requires that the pointer has been created with a PSafeCollection
892 object so that it can enumerate the collection.
893 */
894 T * operator++()
895 {
896 BaseClass::Next();
897 return (T *)BaseClass::currentObject;
898 }
899
900 /**Post-decrement the pointer.
901 This requires that the pointer has been created with a PSafeCollection
902 object so that it can enumerate the collection.
903 */
904 T * operator--(int)
905 {
906 T * previous = (T *)BaseClass::currentObject;
907 BaseClass::Previous();
908 return previous;
909 }
910
911 /**Pre-decrement the pointer.
912 This requires that the pointer has been created with a PSafeCollection
913 object so that it can enumerate the collection.
914 */
915 T * operator--()
916 {
917 BaseClass::Previous();
918 return (T *)BaseClass::currentObject;
919 }
920 //@}
921 };
922
923
924 /**Cast the pointer to a different type. The pointer being cast to MUST
925 be a derived class or NULL is returned.
926 */
927 template <class Base, class Derived>
PSafePtrCast(const PSafePtr<Base> & oldPtr)928 PSafePtr<Derived> PSafePtrCast(const PSafePtr<Base> & oldPtr)
929 {
930 // return PSafePtr<Derived>::DownCast<Base>(oldPtr);
931 PSafePtr<Derived> newPtr;
932 Base * realPtr = oldPtr;
933 if (realPtr != NULL && PIsDescendant(realPtr, Derived))
934 newPtr.Assign(oldPtr);
935 return newPtr;
936 }
937
938
939 /** This class defines a thread-safe collection of objects.
940
941 This is part of a set of classes to solve the general problem of a
942 collection (eg a PList or PDictionary) of objects that needs to be a made
943 thread safe. Any thread can add, read, write or remove an object with both
944 the object and the database of objects itself kept thread safe.
945
946 See the PSafeObject class for more details. Especially in regard to
947 enumeration of collections.
948 */
949 template <class Coll, class Base> class PSafeColl : public PSafeCollection
950 {
951 PCLASSINFO(PSafeColl, PSafeCollection);
952 public:
953 /**@name Construction */
954 //@{
955 /**Create a safe list collection wrapper around the real collection.
956 */
PSafeColl()957 PSafeColl()
958 : PSafeCollection(new Coll)
959 { }
960
961 /**Copy constructor for safe collection.
962 Note the left hand side will always have DisallowDeleteObjects() set.
963 */
PSafeColl(const PSafeColl & other)964 PSafeColl(const PSafeColl & other)
965 : PSafeCollection(new Coll)
966 {
967 PWaitAndSignal lock2(other.collectionMutex);
968 CopySafeCollection(dynamic_cast<Coll *>(other.collection));
969 }
970
971 /**Assign one safe collection to another.
972 Note the left hand side will always have DisallowDeleteObjects() set.
973 */
974 PSafeColl & operator=(const PSafeColl & other)
975 {
976 if (&other != this) {
977 RemoveAll(true);
978 PWaitAndSignal lock1(collectionMutex);
979 PWaitAndSignal lock2(other.collectionMutex);
980 CopySafeCollection(dynamic_cast<Coll *>(other.collection));
981 }
982 return *this;
983 }
984 //@}
985
986 /**@name Operations */
987 //@{
988 /**Add an object to the collection.
989 This uses the PCollection::Append() function to add the object to the
990 collection, with full mutual exclusion locking on the collection.
991 */
992 virtual PSafePtr<Base> Append(
993 Base * obj, ///< Object to add to safe collection.
994 PSafetyMode mode = PSafeReference ///< Safety mode for returned locked PSafePtr
995 ) {
996 PWaitAndSignal mutex(collectionMutex);
997 if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
998 obj->SafeReference())
999 return PSafePtr<Base>(*this, mode, collection->Append(obj));
1000 return NULL;
1001 }
1002
1003 /**Remove an object to the collection.
1004 This function removes the object from the collection itself, but does
1005 not actually delete the object. It simply moves the object to a list
1006 of objects to be garbage collected at a later time.
1007
1008 As for Append() full mutual exclusion locking on the collection itself
1009 is maintained.
1010 */
Remove(Base * obj)1011 virtual PBoolean Remove(
1012 Base * obj ///< Object to remove from safe collection
1013 ) {
1014 return SafeRemove(obj);
1015 }
1016
1017 /**Remove an object to the collection.
1018 This function removes the object from the collection itself, but does
1019 not actually delete the object. It simply moves the object to a list
1020 of objects to be garbage collected at a later time.
1021
1022 As for Append() full mutual exclusion locking on the collection itself
1023 is maintained.
1024 */
RemoveAt(PINDEX idx)1025 virtual PBoolean RemoveAt(
1026 PINDEX idx ///< Index to remove
1027 ) {
1028 return SafeRemoveAt(idx);
1029 }
1030
1031 /**Get the instance in the collection of the index.
1032 The returned safe pointer will increment the reference count on the
1033 PSafeObject and lock to the object in the mode specified. The lock
1034 will remain until the PSafePtr goes out of scope.
1035 */
1036 virtual PSafePtr<Base> GetAt(
1037 PINDEX idx,
1038 PSafetyMode mode = PSafeReadWrite
1039 ) {
1040 return PSafePtr<Base>(*this, mode, idx);
1041 }
1042
1043 /**Find the instance in the collection of an object with the same value.
1044 The returned safe pointer will increment the reference count on the
1045 PSafeObject and lock to the object in the mode specified. The lock
1046 will remain until the PSafePtr goes out of scope.
1047 */
1048 virtual PSafePtr<Base> FindWithLock(
1049 const Base & value,
1050 PSafetyMode mode = PSafeReadWrite
1051 ) {
1052 collectionMutex.Wait();
1053 PSafePtr<Base> ptr(*this, PSafeReference, collection->GetValuesIndex(value));
1054 collectionMutex.Signal();
1055 ptr.SetSafetyMode(mode);
1056 return ptr;
1057 }
1058 //@}
1059 };
1060
1061
1062 /** This class defines a thread-safe array of objects.
1063 See the PSafeObject class for more details. Especially in regard to
1064 enumeration of collections.
1065 */
1066 template <class Base> class PSafeArray : public PSafeColl<PArray<Base>, Base>
1067 {
1068 public:
1069 typedef PSafePtr<Base> value_type;
1070 };
1071
1072
1073 /** This class defines a thread-safe list of objects.
1074 See the PSafeObject class for more details. Especially in regard to
1075 enumeration of collections.
1076 */
1077 template <class Base> class PSafeList : public PSafeColl<PList<Base>, Base>
1078 {
1079 public:
1080 typedef PSafePtr<Base> value_type;
1081 };
1082
1083
1084 /** This class defines a thread-safe sorted array of objects.
1085 See the PSafeObject class for more details. Especially in regard to
1086 enumeration of collections.
1087 */
1088 template <class Base> class PSafeSortedList : public PSafeColl<PSortedList<Base>, Base>
1089 {
1090 public:
1091 typedef PSafePtr<Base> value_type;
1092 };
1093
1094
1095 /** This class defines a thread-safe dictionary of objects.
1096
1097 This is part of a set of classes to solve the general problem of a
1098 collection (eg a PList or PDictionary) of objects that needs to be a made
1099 thread safe. Any thread can add, read, write or remove an object with both
1100 the object and the database of objects itself kept thread safe.
1101
1102 See the PSafeObject class for more details. Especially in regard to
1103 enumeration of collections.
1104 */
1105 template <class Coll, class Key, class Base> class PSafeDictionaryBase : public PSafeCollection
1106 {
1107 PCLASSINFO(PSafeDictionaryBase, PSafeCollection);
1108 public:
1109 /**@name Construction */
1110 //@{
1111 /**Create a safe dictionary wrapper around the real collection.
1112 */
PSafeDictionaryBase()1113 PSafeDictionaryBase()
1114 : PSafeCollection(new Coll) { }
1115
1116 /**Copy constructor for safe collection.
1117 Note the left hand side will always have DisallowDeleteObjects() set.
1118 */
PSafeDictionaryBase(const PSafeDictionaryBase & other)1119 PSafeDictionaryBase(const PSafeDictionaryBase & other)
1120 : PSafeCollection(new Coll)
1121 {
1122 PWaitAndSignal lock2(other.collectionMutex);
1123 CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1124 }
1125
1126 /**Assign one safe collection to another.
1127 Note the left hand side will always have DisallowDeleteObjects() set.
1128 */
1129 PSafeDictionaryBase & operator=(const PSafeDictionaryBase & other)
1130 {
1131 if (&other != this) {
1132 RemoveAll(true);
1133 PWaitAndSignal lock1(collectionMutex);
1134 PWaitAndSignal lock2(other.collectionMutex);
1135 CopySafeDictionary(dynamic_cast<Coll *>(other.collection));
1136 }
1137 return *this;
1138 }
1139 //@}
1140
1141 /**@name Operations */
1142 //@{
1143 /**Add an object to the collection.
1144 This uses the PCollection::Append() function to add the object to the
1145 collection, with full mutual exclusion locking on the collection.
1146 */
SetAt(const Key & key,Base * obj)1147 virtual void SetAt(const Key & key, Base * obj)
1148 {
1149 collectionMutex.Wait();
1150 SafeRemove(((Coll *)collection)->GetAt(key));
1151 if (PAssert(collection->GetObjectsIndex(obj) == P_MAX_INDEX, "Cannot insert safe object twice") &&
1152 obj->SafeReference())
1153 ((Coll *)collection)->SetAt(key, obj);
1154 collectionMutex.Signal();
1155 }
1156
1157 /**Remove an object to the collection.
1158 This function removes the object from the collection itself, but does
1159 not actually delete the object. It simply moves the object to a list
1160 of objects to be garbage collected at a later time.
1161
1162 As for Append() full mutual exclusion locking on the collection itself
1163 is maintained.
1164 */
RemoveAt(const Key & key)1165 virtual PBoolean RemoveAt(
1166 const Key & key ///< Key to fund object to delete
1167 ) {
1168 PWaitAndSignal mutex(collectionMutex);
1169 return SafeRemove(((Coll *)collection)->GetAt(key));
1170 }
1171
1172 /**Determine of the dictionary contains an entry for the key.
1173 */
Contains(const Key & key)1174 virtual PBoolean Contains(
1175 const Key & key
1176 ) {
1177 PWaitAndSignal lock(collectionMutex);
1178 return ((Coll *)collection)->Contains(key);
1179 }
1180
1181 /**Get the instance in the collection of the index.
1182 The returned safe pointer will increment the reference count on the
1183 PSafeObject and lock to the object in the mode specified. The lock
1184 will remain until the PSafePtr goes out of scope.
1185 */
1186 virtual PSafePtr<Base> GetAt(
1187 PINDEX idx,
1188 PSafetyMode mode = PSafeReadWrite
1189 ) {
1190 return PSafePtr<Base>(*this, mode, idx);
1191 }
1192
1193 /**Find the instance in the collection of an object with the same value.
1194 The returned safe pointer will increment the reference count on the
1195 PSafeObject and lock to the object in the mode specified. The lock
1196 will remain until the PSafePtr goes out of scope.
1197 */
1198 virtual PSafePtr<Base> FindWithLock(
1199 const Key & key,
1200 PSafetyMode mode = PSafeReadWrite
1201 ) {
1202 collectionMutex.Wait();
1203 PSafePtr<Base> ptr(*this, PSafeReference, ((Coll *)collection)->GetAt(key));
1204 collectionMutex.Signal();
1205 ptr.SetSafetyMode(mode);
1206 return ptr;
1207 }
1208
1209 /**Get an array containing all the keys for the dictionary.
1210 */
GetKeys()1211 PArray<Key> GetKeys() const
1212 {
1213 PArray<Key> keys;
1214 collectionMutex.Wait();
1215 ((Coll *)collection)->AbstractGetKeys(keys);
1216 collectionMutex.Signal();
1217 return keys;
1218 }
1219 //@}
1220 };
1221
1222
1223 /** This class defines a thread-safe array of objects.
1224 See the PSafeObject class for more details. Especially in regard to
1225 enumeration of collections.
1226 */
1227 template <class Key, class Base> class PSafeDictionary : public PSafeDictionaryBase<PDictionary<Key, Base>, Key, Base>
1228 {
1229 public:
1230 typedef PSafePtr<Base> value_type;
1231 };
1232
1233
1234 #endif // PTLIB_SAFE_COLLECTION_H
1235
1236
1237 // End Of File ///////////////////////////////////////////////////////////////
1238