From 936edacc92b79d6659030679090032188b2bbc8e Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 19 Jun 2008 17:30:38 +0000 Subject: [PATCH] From Mathias Froehlich, added support for using OpenThreads::Atomic for thread safe ref/unref. --- include/osg/Referenced | 33 ++++++++++++++++-- src/osg/Referenced.cpp | 77 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/include/osg/Referenced b/include/osg/Referenced index 323ea382a..357c13689 100644 --- a/include/osg/Referenced +++ b/include/osg/Referenced @@ -30,6 +30,10 @@ #include #endif +#include +#if !defined(_OPENTHREADS_ATOMIC_USE_MUTEX) +# define _OSG_REFERENCED_USE_ATOMIC_OPERATIONS +#endif namespace osg { @@ -57,10 +61,19 @@ class OSG_EXPORT Referenced virtual void setThreadSafeRefUnref(bool threadSafe); /** 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; } +#endif /** 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; } +#endif /** Increment the reference count by one, indicating that this object has another pointer which is referencing it.*/ @@ -112,17 +125,28 @@ class OSG_EXPORT Referenced virtual ~Referenced(); void deleteUsingDeleteHandler() const; + +#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) + struct ObserverSetData; + + OpenThreads::AtomicPtr _observerSetDataPtr; + + mutable OpenThreads::Atomic _refCount; +#else mutable OpenThreads::Mutex* _refMutex; mutable int _refCount; - void* _observers; - + void* _observers; +#endif }; inline void Referenced::ref() const { +#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) + ++_refCount; +#else if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); @@ -132,10 +156,14 @@ inline void Referenced::ref() const { ++_refCount; } +#endif } inline void Referenced::unref() const { +#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) + bool needDelete = (--_refCount == 0); +#else bool needDelete = false; if (_refMutex) { @@ -148,6 +176,7 @@ inline void Referenced::unref() const --_refCount; needDelete = _refCount<=0; } +#endif if (needDelete) { diff --git a/src/osg/Referenced.cpp b/src/osg/Referenced.cpp index 6168712eb..c8bd6dac8 100644 --- a/src/osg/Referenced.cpp +++ b/src/osg/Referenced.cpp @@ -82,8 +82,14 @@ struct DeleteHandlerPointer typedef std::set 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; +#endif // static std::auto_ptr s_deleteHandler(0); static DeleteHandlerPointer s_deleteHandler(0); @@ -91,12 +97,18 @@ static ApplicationUsageProxy Referenced_e0(ApplicationUsage::ENVIRONMENTAL_VARIA void Referenced::setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting) { +#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) s_useThreadSafeReferenceCounting = enableThreadSafeReferenceCounting; +#endif } bool Referenced::getThreadSafeReferenceCounting() { +#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) + return true; +#else return s_useThreadSafeReferenceCounting; +#endif } @@ -120,14 +132,21 @@ static int s_numObjects = 0; #endif Referenced::Referenced(): +#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) + _observerSetDataPtr(0), + _refCount(0) +#else _refMutex(0), _refCount(0), _observers(0) +#endif { +#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) #ifndef ENFORCE_THREADSAFE if (s_useThreadSafeReferenceCounting) #endif _refMutex = new OpenThreads::Mutex; +#endif #ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION { @@ -140,16 +159,21 @@ Referenced::Referenced(): } Referenced::Referenced(bool threadSafeRefUnref): +#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) + _observerSetDataPtr(0), + _refCount(0) +#else _refMutex(0), _refCount(0), _observers(0) +#endif { - // if (!threadSafeRefUnref) osg::notify(osg::NOTICE)<<"Not ThreadSaef "<(_observers); @@ -214,10 +246,25 @@ Referenced::~Referenced() _refMutex = 0; 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) { +#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) if (threadSafe) { if (!_refMutex) @@ -236,11 +283,13 @@ void Referenced::setThreadSafeRefUnref(bool threadSafe) delete tmpMutexPtr; } } +#endif } void Referenced::unref_nodelete() const { +#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); @@ -250,10 +299,24 @@ void Referenced::unref_nodelete() const { --_refCount; } +#else + --_refCount; +#endif } 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 lock(observerSetData->_mutex); + observerSetData->_observers.insert(observer); +#else if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); @@ -266,10 +329,19 @@ void Referenced::addObserver(Observer* observer) if (!_observers) _observers = new ObserverSet; if (_observers) static_cast(_observers)->insert(observer); } +#endif } void Referenced::removeObserver(Observer* observer) { +#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) + ObserverSetData* observerSetData = _observerSetDataPtr.get(); + if (observerSetData) + { + OpenThreads::ScopedLock lock(observerSetData->_mutex); + observerSetData->_observers.erase(observer); + } +#else if (_refMutex) { OpenThreads::ScopedLock lock(*_refMutex); @@ -280,6 +352,7 @@ void Referenced::removeObserver(Observer* observer) { if (_observers) static_cast(_observers)->erase(observer); } +#endif } void Referenced::deleteUsingDeleteHandler() const