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