📄 safecoll.cxx
字号:
/*
* safecoll.cxx
*
* 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): ______________________________________.
*
* $Log: safecoll.cxx,v $
* Revision 1.1 2006/06/29 04:18:19 joegenbaclor
* *** empty log message ***
*
* Revision 1.14 2004/10/14 23:01:31 csoutheren
* Fiuxed problem with usage of Sleep
*
* Revision 1.13 2004/10/14 12:31:47 rjongbloed
* Added synchronous mode for safe collection RemoveAll() to wait until all objects
* have actually been deleted before returning.
*
* Revision 1.12 2004/10/04 12:54:33 rjongbloed
* Added functions for locking an unlocking to "auto-unlock" classes.
*
* Revision 1.11 2004/08/14 07:42:31 rjongbloed
* Added trace log at level 6 for helping find PSafeObject reference/dereference errors.
*
* Revision 1.10 2004/08/12 12:37:41 rjongbloed
* Fixed bug recently introduced so removes deleted object from deletion list.
* Also changed removal list to be correct type.
*
* Revision 1.9 2004/08/05 12:15:56 rjongbloed
* Added classes for auto unlocking read only and read write mutex on
* PSafeObject - similar to PWaitAndSIgnal.
* Utilised mutable keyword for mutex and improved the constness of functions.
* Added DisallowDeleteObjects to safe collections so can have a PSafeObject in
* multiple collections.
* Added a tempalte function to do casting of PSafePtr to a PSafePtr of a derived
* class.
* Assured that a PSafeObject present on a collection always increments its
* reference count so while in collection it is not deleted.
*
* Revision 1.8 2004/04/03 08:22:22 csoutheren
* Remove pseudo-RTTI and replaced with real RTTI
*
* Revision 1.7 2002/12/10 07:37:34 robertj
* optimised SetLockMode() so if doesn't change mode it doesn't do anything.
*
* Revision 1.6 2002/10/29 00:06:24 robertj
* Changed template classes so things like PSafeList actually creates the
* base collection class as well.
* Allowed for the PSafeList::Append() to return a locked pointer to the
* object just appended.
*
* Revision 1.5 2002/10/04 08:22:50 robertj
* Changed read/write mutex so can be called by same thread without deadlock
* removing the need to a lock count in safe pointer.
* Added asserts if try and dereference a NULL safe pointer.
* Added more documentation on behaviour.
*
* Revision 1.4 2002/08/29 06:53:28 robertj
* Added optimisiation, separate mutex for toBeRemoved list.
* Added assert for reference count going below zero.
* Fixed incorrect usage of lockCount if target of an assignment from another
* safe pointer. Would not unlock the safe object which could cause deadlock.
*
* Revision 1.3 2002/05/06 00:44:45 robertj
* Made the lock/unlock read only const so can be used in const functions.
*
* Revision 1.2 2002/05/01 04:48:05 robertj
* GNU compatibility.
*
* Revision 1.1 2002/05/01 04:16:44 robertj
* Added thread safe collection classes.
*
*/
#ifdef __GNUC__
#pragma implementation "safecoll.h"
#endif
#include <ptlib.h>
#include <ptlib/safecoll.h>
#define new PNEW
/////////////////////////////////////////////////////////////////////////////
PSafeObject::PSafeObject()
{
safeReferenceCount = 0;
safelyBeingRemoved = FALSE;
}
BOOL PSafeObject::SafeReference()
{
PWaitAndSignal mutex(safetyMutex);
if (safelyBeingRemoved)
return FALSE;
safeReferenceCount++;
PTRACE(6, "SafeColl\tIncrement reference count to " << safeReferenceCount << " for " << GetClass() << ' ' << (void *)this);
return TRUE;
}
void PSafeObject::SafeDereference()
{
safetyMutex.Wait();
if (PAssert(safeReferenceCount > 0, PLogicError)) {
safeReferenceCount--;
PTRACE(6, "SafeColl\tDecrement reference count to " << safeReferenceCount << " for " << GetClass() << ' ' << (void *)this);
}
safetyMutex.Signal();
}
BOOL PSafeObject::LockReadOnly() const
{
safetyMutex.Wait();
if (safelyBeingRemoved) {
safetyMutex.Signal();
return FALSE;
}
safetyMutex.Signal();
safeInUseFlag.StartRead();
return TRUE;
}
void PSafeObject::UnlockReadOnly() const
{
safeInUseFlag.EndRead();
}
BOOL PSafeObject::LockReadWrite()
{
safetyMutex.Wait();
if (safelyBeingRemoved) {
safetyMutex.Signal();
return FALSE;
}
safetyMutex.Signal();
safeInUseFlag.StartWrite();
return TRUE;
}
void PSafeObject::UnlockReadWrite()
{
safeInUseFlag.EndWrite();
}
void PSafeObject::SafeRemove()
{
safetyMutex.Wait();
safelyBeingRemoved = TRUE;
safetyMutex.Signal();
}
BOOL PSafeObject::SafelyCanBeDeleted() const
{
PWaitAndSignal mutex(safetyMutex);
return safelyBeingRemoved && safeReferenceCount == 0;
}
/////////////////////////////////////////////////////////////////////////////
PSafeLockReadOnly::PSafeLockReadOnly(const PSafeObject & object)
: safeObject((PSafeObject &)object)
{
locked = safeObject.LockReadOnly();
}
PSafeLockReadOnly::~PSafeLockReadOnly()
{
if (locked)
safeObject.UnlockReadOnly();
}
BOOL PSafeLockReadOnly::Lock()
{
locked = safeObject.LockReadOnly();
return locked;
}
void PSafeLockReadOnly::Unlock()
{
if (locked) {
safeObject.UnlockReadOnly();
locked = FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
PSafeLockReadWrite::PSafeLockReadWrite(const PSafeObject & object)
: safeObject((PSafeObject &)object)
{
locked = safeObject.LockReadWrite();
}
PSafeLockReadWrite::~PSafeLockReadWrite()
{
if (locked)
safeObject.UnlockReadWrite();
}
BOOL PSafeLockReadWrite::Lock()
{
locked = safeObject.LockReadWrite();
return locked;
}
void PSafeLockReadWrite::Unlock()
{
if (locked) {
safeObject.UnlockReadWrite();
locked = FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
PSafeCollection::PSafeCollection(PCollection * coll)
{
collection = coll;
collection->DisallowDeleteObjects();
toBeRemoved.DisallowDeleteObjects();
deleteObjects = TRUE;
}
PSafeCollection::~PSafeCollection()
{
deleteObjectsTimer.Stop();
toBeRemoved.AllowDeleteObjects();
toBeRemoved.RemoveAll();
collection->AllowDeleteObjects();
delete collection;
}
BOOL PSafeCollection::SafeRemove(PSafeObject * obj)
{
if (obj == NULL)
return FALSE;
PWaitAndSignal mutex(collectionMutex);
if (!collection->Remove(obj))
return FALSE;
SafeRemoveObject(obj);
return TRUE;
}
BOOL PSafeCollection::SafeRemoveAt(PINDEX idx)
{
PWaitAndSignal mutex(collectionMutex);
PSafeObject * obj = PDownCast(PSafeObject, collection->RemoveAt(idx));
if (obj == NULL)
return FALSE;
SafeRemoveObject(obj);
return TRUE;
}
void PSafeCollection::RemoveAll(BOOL synchronous)
{
collectionMutex.Wait();
while (collection->GetSize() > 0)
SafeRemoveObject(PDownCast(PSafeObject, collection->RemoveAt(0)));
collectionMutex.Signal();
if (synchronous) {
// Have unfortunate busy loop here, but it should be very
// rare that it will be here for long
while (!DeleteObjectsToBeRemoved())
PThread::Sleep(100);
}
}
void PSafeCollection::SafeRemoveObject(PSafeObject * obj)
{
if (obj == NULL)
return;
obj->SafeDereference();
if (!deleteObjects)
return;
obj->SafeRemove();
removalMutex.Wait();
toBeRemoved.Append(obj);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -