From Mathias Froehlich, added support for using OpenThreads::Atomic for thread safe ref/unref.

This commit is contained in:
Robert Osfield 2008-06-19 17:30:38 +00:00
parent 2ba5f002d2
commit 936edacc92
2 changed files with 106 additions and 4 deletions

View File

@ -30,6 +30,10 @@
#include <OpenThreads/Mutex> #include <OpenThreads/Mutex>
#endif #endif
#include <OpenThreads/Atomic>
#if !defined(_OPENTHREADS_ATOMIC_USE_MUTEX)
# define _OSG_REFERENCED_USE_ATOMIC_OPERATIONS
#endif
namespace osg { namespace osg {
@ -57,10 +61,19 @@ class OSG_EXPORT Referenced
virtual void setThreadSafeRefUnref(bool threadSafe); virtual void setThreadSafeRefUnref(bool threadSafe);
/** Get whether a mutex is used to ensure ref() and unref() are thread safe.*/ /** Get whether a mutex is used to ensure ref() and unref() are thread safe.*/
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
bool getThreadSafeRefUnref() const { return true; }
#else
bool getThreadSafeRefUnref() const { return _refMutex!=0; } bool getThreadSafeRefUnref() const { return _refMutex!=0; }
#endif
/** Get the mutex used to ensure thread safety of ref()/unref(). */ /** Get the mutex used to ensure thread safety of ref()/unref(). */
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
OpenThreads::Mutex* getRefMutex() const { return 0; }
#else
OpenThreads::Mutex* getRefMutex() const { return _refMutex; } OpenThreads::Mutex* getRefMutex() const { return _refMutex; }
#endif
/** Increment the reference count by one, indicating that /** Increment the reference count by one, indicating that
this object has another pointer which is referencing it.*/ this object has another pointer which is referencing it.*/
@ -113,16 +126,27 @@ class OSG_EXPORT Referenced
void deleteUsingDeleteHandler() const; void deleteUsingDeleteHandler() const;
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
struct ObserverSetData;
OpenThreads::AtomicPtr<ObserverSetData> _observerSetDataPtr;
mutable OpenThreads::Atomic _refCount;
#else
mutable OpenThreads::Mutex* _refMutex; mutable OpenThreads::Mutex* _refMutex;
mutable int _refCount; mutable int _refCount;
void* _observers; void* _observers;
#endif
}; };
inline void Referenced::ref() const inline void Referenced::ref() const
{ {
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
++_refCount;
#else
if (_refMutex) if (_refMutex)
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
@ -132,10 +156,14 @@ inline void Referenced::ref() const
{ {
++_refCount; ++_refCount;
} }
#endif
} }
inline void Referenced::unref() const inline void Referenced::unref() const
{ {
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
bool needDelete = (--_refCount == 0);
#else
bool needDelete = false; bool needDelete = false;
if (_refMutex) if (_refMutex)
{ {
@ -148,6 +176,7 @@ inline void Referenced::unref() const
--_refCount; --_refCount;
needDelete = _refCount<=0; needDelete = _refCount<=0;
} }
#endif
if (needDelete) if (needDelete)
{ {

View File

@ -82,8 +82,14 @@ struct DeleteHandlerPointer
typedef std::set<Observer*> ObserverSet; typedef std::set<Observer*> ObserverSet;
struct Referenced::ObserverSetData {
OpenThreads::Mutex _mutex;
ObserverSet _observers;
};
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0; static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0;
#endif
// static std::auto_ptr<DeleteHandler> s_deleteHandler(0); // static std::auto_ptr<DeleteHandler> s_deleteHandler(0);
static DeleteHandlerPointer s_deleteHandler(0); static DeleteHandlerPointer s_deleteHandler(0);
@ -91,12 +97,18 @@ static ApplicationUsageProxy Referenced_e0(ApplicationUsage::ENVIRONMENTAL_VARIA
void Referenced::setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting) void Referenced::setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting)
{ {
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
s_useThreadSafeReferenceCounting = enableThreadSafeReferenceCounting; s_useThreadSafeReferenceCounting = enableThreadSafeReferenceCounting;
#endif
} }
bool Referenced::getThreadSafeReferenceCounting() bool Referenced::getThreadSafeReferenceCounting()
{ {
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
return true;
#else
return s_useThreadSafeReferenceCounting; return s_useThreadSafeReferenceCounting;
#endif
} }
@ -120,14 +132,21 @@ static int s_numObjects = 0;
#endif #endif
Referenced::Referenced(): Referenced::Referenced():
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_observerSetDataPtr(0),
_refCount(0)
#else
_refMutex(0), _refMutex(0),
_refCount(0), _refCount(0),
_observers(0) _observers(0)
#endif
{ {
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE #ifndef ENFORCE_THREADSAFE
if (s_useThreadSafeReferenceCounting) if (s_useThreadSafeReferenceCounting)
#endif #endif
_refMutex = new OpenThreads::Mutex; _refMutex = new OpenThreads::Mutex;
#endif
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION #ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
{ {
@ -140,16 +159,21 @@ Referenced::Referenced():
} }
Referenced::Referenced(bool threadSafeRefUnref): Referenced::Referenced(bool threadSafeRefUnref):
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_observerSetDataPtr(0),
_refCount(0)
#else
_refMutex(0), _refMutex(0),
_refCount(0), _refCount(0),
_observers(0) _observers(0)
#endif
{ {
// if (!threadSafeRefUnref) osg::notify(osg::NOTICE)<<"Not ThreadSaef "<<std::endl; #if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE #ifndef ENFORCE_THREADSAFE
if (threadSafeRefUnref) if (threadSafeRefUnref)
#endif #endif
_refMutex = new OpenThreads::Mutex; _refMutex = new OpenThreads::Mutex;
#endif
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION #ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
{ {
@ -161,14 +185,21 @@ Referenced::Referenced(bool threadSafeRefUnref):
} }
Referenced::Referenced(const Referenced&): Referenced::Referenced(const Referenced&):
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
_observerSetDataPtr(0),
_refCount(0)
#else
_refMutex(0), _refMutex(0),
_refCount(0), _refCount(0),
_observers(0) _observers(0)
#endif
{ {
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
#ifndef ENFORCE_THREADSAFE #ifndef ENFORCE_THREADSAFE
if (s_useThreadSafeReferenceCounting) if (s_useThreadSafeReferenceCounting)
#endif #endif
_refMutex = new OpenThreads::Mutex; _refMutex = new OpenThreads::Mutex;
#endif
#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION #ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
{ {
@ -195,6 +226,7 @@ Referenced::~Referenced()
notify(WARN)<<" the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl; notify(WARN)<<" the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl;
} }
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
if (_observers) if (_observers)
{ {
ObserverSet* os = static_cast<ObserverSet*>(_observers); ObserverSet* os = static_cast<ObserverSet*>(_observers);
@ -214,10 +246,25 @@ Referenced::~Referenced()
_refMutex = 0; _refMutex = 0;
delete tmpMutexPtr; delete tmpMutexPtr;
} }
#else
ObserverSetData* observerSetData = _observerSetDataPtr.get();
if (observerSetData)
{
for(ObserverSet::iterator itr = observerSetData->_observers.begin();
itr != observerSetData->_observers.end();
++itr)
{
(*itr)->objectDeleted(this);
}
_observerSetDataPtr.assign(0, observerSetData);
delete observerSetData;
}
#endif
} }
void Referenced::setThreadSafeRefUnref(bool threadSafe) void Referenced::setThreadSafeRefUnref(bool threadSafe)
{ {
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
if (threadSafe) if (threadSafe)
{ {
if (!_refMutex) if (!_refMutex)
@ -236,11 +283,13 @@ void Referenced::setThreadSafeRefUnref(bool threadSafe)
delete tmpMutexPtr; delete tmpMutexPtr;
} }
} }
#endif
} }
void Referenced::unref_nodelete() const void Referenced::unref_nodelete() const
{ {
#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
if (_refMutex) if (_refMutex)
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
@ -250,10 +299,24 @@ void Referenced::unref_nodelete() const
{ {
--_refCount; --_refCount;
} }
#else
--_refCount;
#endif
} }
void Referenced::addObserver(Observer* observer) void Referenced::addObserver(Observer* observer)
{ {
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
ObserverSetData* observerSetData = _observerSetDataPtr.get();
while (0 == observerSetData) {
ObserverSetData* newObserverSetData = new ObserverSetData;
if (!_observerSetDataPtr.assign(newObserverSetData, 0))
delete newObserverSetData;
observerSetData = _observerSetDataPtr.get();
}
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(observerSetData->_mutex);
observerSetData->_observers.insert(observer);
#else
if (_refMutex) if (_refMutex)
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
@ -266,10 +329,19 @@ void Referenced::addObserver(Observer* observer)
if (!_observers) _observers = new ObserverSet; if (!_observers) _observers = new ObserverSet;
if (_observers) static_cast<ObserverSet*>(_observers)->insert(observer); if (_observers) static_cast<ObserverSet*>(_observers)->insert(observer);
} }
#endif
} }
void Referenced::removeObserver(Observer* observer) void Referenced::removeObserver(Observer* observer)
{ {
#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
ObserverSetData* observerSetData = _observerSetDataPtr.get();
if (observerSetData)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(observerSetData->_mutex);
observerSetData->_observers.erase(observer);
}
#else
if (_refMutex) if (_refMutex)
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex); OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
@ -280,6 +352,7 @@ void Referenced::removeObserver(Observer* observer)
{ {
if (_observers) static_cast<ObserverSet*>(_observers)->erase(observer); if (_observers) static_cast<ObserverSet*>(_observers)->erase(observer);
} }
#endif
} }
void Referenced::deleteUsingDeleteHandler() const void Referenced::deleteUsingDeleteHandler() const