Added an osgDB::ReadWriteMutex to help manage the ability to have serialize

write to objects but allow multiple threads to read at once in a read only way.
This commit is contained in:
Robert Osfield
2006-12-27 16:40:34 +00:00
parent cd133e5f2c
commit 30cb8735d3
8 changed files with 140 additions and 18 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -30,6 +30,8 @@
#include <osg/Vec3>
#include <osg/BoundingBox>
#include <osgDB/ReentrantMutex>
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

View File

@@ -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

View File

@@ -12,7 +12,9 @@
*/
#include <osgDB/ReentrantMutex>
#include <OpenThreads/ScopedLock>
#include <osg/Notify>
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."<<std::endl;
}
#else
if (_lockCount>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<OpenThreads::Mutex> lock(_readCountMutex);
int result = 0;
if (_readCount==0)
{
result = _readWriteMutex.lock();
}
++_readCount;
return result;
}
int ReadWriteMutex::readUnlock()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> 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();
}

View File

@@ -64,13 +64,14 @@ void osgParticle::ParticleProcessor::traverse(osg::NodeVisitor& nv)
{
if (nv.getFrameStamp())
{
OpenThreads::ScopedLock<OpenThreads::Mutex> 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();

View File

@@ -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();

View File

@@ -27,32 +27,30 @@ void osgParticle::ParticleSystemUpdater::traverse(osg::NodeVisitor& nv)
{
if (nv.getFrameStamp())
{
OpenThreads::ScopedLock<OpenThreads::Mutex> 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
{