diff --git a/include/osgDB/ReentrantMutex b/include/osgDB/ReentrantMutex index 222c5819c..1307bd8bb 100644 --- a/include/osgDB/ReentrantMutex +++ b/include/osgDB/ReentrantMutex @@ -37,15 +37,70 @@ class OSGDB_EXPORT ReentrantMutex : public OpenThreads::Mutex private: - ReentrantMutex(const ReentrantMutex &):OpenThreads::Mutex() {} + ReentrantMutex(const ReentrantMutex&):OpenThreads::Mutex() {} - ReentrantMutex &operator=(const ReentrantMutex &) {return *(this);} + ReentrantMutex& operator =(const ReentrantMutex&) { return *(this); } OpenThreads::Thread* _threadHoldingMutex; unsigned int _lockCount; }; +class OSGDB_EXPORT ReadWriteMutex +{ + public: + + ReadWriteMutex(); + + virtual ~ReadWriteMutex(); + + virtual int readLock(); + + virtual int readUnlock(); + + virtual int writeLock(); + + virtual int writeUnlock(); + + protected: + + ReadWriteMutex(const ReadWriteMutex&) {} + ReadWriteMutex& operator = (const ReadWriteMutex&) { return *(this); } + +#if 1 + ReentrantMutex _readWriteMutex; + ReentrantMutex _readCountMutex; +#else + OpenThreads::Mutex _readWriteMutex; + OpenThreads::Mutex _readCountMutex; +#endif + unsigned int _readCount; + +}; + +class ScopedReadLock +{ + public: + + ScopedReadLock(ReadWriteMutex& mutex):_mutex(mutex) { _mutex.readLock(); } + ~ScopedReadLock() { _mutex.readUnlock(); } + + protected: + ReadWriteMutex& _mutex; +}; + + +class ScopedWriteLock +{ + public: + + ScopedWriteLock(ReadWriteMutex& mutex):_mutex(mutex) { _mutex.writeLock(); } + ~ScopedWriteLock() { _mutex.writeUnlock(); } + + protected: + ReadWriteMutex& _mutex; +}; + } #endif diff --git a/include/osgParticle/ParticleProcessor b/include/osgParticle/ParticleProcessor index 2a20a5255..c2b23913b 100644 --- a/include/osgParticle/ParticleProcessor +++ b/include/osgParticle/ParticleProcessor @@ -171,8 +171,6 @@ namespace osgParticle //added- 1/17/06- bgandere@nps.edu //a var to keep from doing multiple updates int _frameNumber; - - OpenThreads::Mutex _cullUpdatelMutex; }; // INLINE FUNCTIONS diff --git a/include/osgParticle/ParticleSystem b/include/osgParticle/ParticleSystem index 9e0ea3a58..67f3ffb4e 100644 --- a/include/osgParticle/ParticleSystem +++ b/include/osgParticle/ParticleSystem @@ -30,6 +30,8 @@ #include #include +#include + namespace osgParticle { @@ -163,6 +165,8 @@ namespace osgParticle virtual void drawImplementation(osg::State& state) const; virtual osg::BoundingBox computeBound() const; + + osgDB::ReadWriteMutex& getReadWriteMutex() const { return _readWriteMutex; } protected: @@ -201,6 +205,8 @@ namespace osgParticle int _detail; mutable int _draw_count; + mutable osgDB::ReadWriteMutex _readWriteMutex; + }; // INLINE FUNCTIONS diff --git a/include/osgParticle/ParticleSystemUpdater b/include/osgParticle/ParticleSystemUpdater index abf3070c2..5ab10886b 100644 --- a/include/osgParticle/ParticleSystemUpdater +++ b/include/osgParticle/ParticleSystemUpdater @@ -91,8 +91,6 @@ namespace osgParticle //added 1/17/06- bgandere@nps.edu //a var to keep from doing multiple updates per frame int _frameNumber; - - OpenThreads::Mutex _cullUpdatelMutex; }; // INLINE FUNCTIONS diff --git a/src/osgDB/ReentrantMutex.cpp b/src/osgDB/ReentrantMutex.cpp index 39a6e0a73..74a652ab8 100644 --- a/src/osgDB/ReentrantMutex.cpp +++ b/src/osgDB/ReentrantMutex.cpp @@ -12,7 +12,9 @@ */ #include +#include +#include using namespace osgDB; using namespace OpenThreads; @@ -48,6 +50,7 @@ int ReentrantMutex::lock() int ReentrantMutex::unlock() { +#if 0 if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0) { --_lockCount; @@ -57,6 +60,21 @@ int ReentrantMutex::unlock() return Mutex::unlock(); } } + else + { + osg::notify(osg::NOTICE)<<"Error: ReentrantMutex::unlock() - unlocking from the wrong thread."<0) + { + --_lockCount; + if (_lockCount<=0) + { + _threadHoldingMutex = 0; + return Mutex::unlock(); + } + } +#endif return 0; } @@ -78,3 +96,49 @@ int ReentrantMutex::trylock() return result; } } + +ReadWriteMutex::ReadWriteMutex(): + _readCount(0) +{ +} + +ReadWriteMutex::~ReadWriteMutex() +{ +} + +int ReadWriteMutex::readLock() +{ + OpenThreads::ScopedLock lock(_readCountMutex); + int result = 0; + if (_readCount==0) + { + result = _readWriteMutex.lock(); + } + ++_readCount; + return result; +} + +int ReadWriteMutex::readUnlock() +{ + OpenThreads::ScopedLock lock(_readCountMutex); + int result = 0; + if (_readCount>0) + { + --_readCount; + if (_readCount==0) + { + result = _readWriteMutex.unlock(); + } + } + return result; +} + +int ReadWriteMutex::writeLock() +{ + return _readWriteMutex.lock(); +} + +int ReadWriteMutex::writeUnlock() +{ + return _readWriteMutex.unlock(); +} diff --git a/src/osgParticle/ParticleProcessor.cpp b/src/osgParticle/ParticleProcessor.cpp index ee15abc0d..bf72416b8 100644 --- a/src/osgParticle/ParticleProcessor.cpp +++ b/src/osgParticle/ParticleProcessor.cpp @@ -64,13 +64,14 @@ void osgParticle::ParticleProcessor::traverse(osg::NodeVisitor& nv) { if (nv.getFrameStamp()) { - OpenThreads::ScopedLock lock(_cullUpdatelMutex); + osgDB::ScopedWriteLock lock(_ps->getReadWriteMutex()); //added- 1/17/06- bgandere@nps.edu //a check to make sure we havent updated yet this frame if(_frameNumber < nv.getFrameStamp()->getFrameNumber()) { + // retrieve the current time double t = nv.getFrameStamp()->getReferenceTime(); diff --git a/src/osgParticle/ParticleSystem.cpp b/src/osgParticle/ParticleSystem.cpp index e4f98dd04..69e1359ae 100644 --- a/src/osgParticle/ParticleSystem.cpp +++ b/src/osgParticle/ParticleSystem.cpp @@ -91,6 +91,8 @@ void osgParticle::ParticleSystem::update(double dt) void osgParticle::ParticleSystem::drawImplementation(osg::State& state) const { + osgDB::ScopedReadLock lock(_readWriteMutex); + // update the frame count, so other objects can detect when // this particle system is culled _last_frame = state.getFrameStamp()->getFrameNumber(); diff --git a/src/osgParticle/ParticleSystemUpdater.cpp b/src/osgParticle/ParticleSystemUpdater.cpp index 75ff99a30..2266fca42 100644 --- a/src/osgParticle/ParticleSystemUpdater.cpp +++ b/src/osgParticle/ParticleSystemUpdater.cpp @@ -27,32 +27,30 @@ void osgParticle::ParticleSystemUpdater::traverse(osg::NodeVisitor& nv) { if (nv.getFrameStamp()) { - - OpenThreads::ScopedLock lock(_cullUpdatelMutex); - //added 1/17/06- bgandere@nps.edu - //ensures ParticleSystem will only be updated once per frame - //regardless of the number of cameras viewing it if( _frameNumber < nv.getFrameStamp()->getFrameNumber()) { + _frameNumber = nv.getFrameStamp()->getFrameNumber(); + double t = nv.getFrameStamp()->getReferenceTime(); - if (_t0 != -1) + if (_t0 != -1.0) { ParticleSystem_Vector::iterator i; for (i=_psv.begin(); i!=_psv.end(); ++i) { - if (!i->get()->isFrozen() && (i->get()->getLastFrameNumber() >= (nv.getFrameStamp()->getFrameNumber() - 1) || !i->get()->getFreezeOnCull())) + ParticleSystem* ps = i->get(); + + osgDB::ScopedWriteLock lock(ps->getReadWriteMutex()); + + if (!ps->isFrozen() && (ps->getLastFrameNumber() >= (nv.getFrameStamp()->getFrameNumber() - 1) || !ps->getFreezeOnCull())) { - i->get()->update(t - _t0); + ps->update(t - _t0); } } } _t0 = t; } - //added- 1/17/06- bgandere@nps.edu - //set frame number to the current frame number - _frameNumber = nv.getFrameStamp()->getFrameNumber(); } else {