From Tim Moore, "This patch fixes a race condition in Renderer::ThreadSafeQueue that was causing some notifications of available SceneView objects to be missed. I saw a very noticeable performance problem (60 fps -> 8 fps) in DrawThreadPerContext mode in an osgEarth application before this patch. I had high hopes that this change might fix the much-discussed multiple GPU problem; no such luck, but I think the root cause of that is probably a similar threading issue."
This commit is contained in:
parent
88987d194a
commit
e4b1b6228d
@ -14,6 +14,7 @@
|
||||
#ifndef OSGVIEWER_RENDERER
|
||||
#define OSGVIEWER_RENDERER 1
|
||||
|
||||
#include <OpenThreads/Condition>
|
||||
#include <osg/Timer>
|
||||
#include <osgDB/DatabasePager>
|
||||
#include <osgUtil/SceneView>
|
||||
@ -89,20 +90,21 @@ class OSGVIEWER_EXPORT Renderer : public osg::GraphicsOperation
|
||||
struct OSGVIEWER_EXPORT ThreadSafeQueue
|
||||
{
|
||||
OpenThreads::Mutex _mutex;
|
||||
OpenThreads::Block _block;
|
||||
OpenThreads::Condition _cond;
|
||||
typedef std::list<osgUtil::SceneView*> SceneViewList;
|
||||
SceneViewList _queue;
|
||||
bool _isReleased;
|
||||
|
||||
ThreadSafeQueue();
|
||||
~ThreadSafeQueue();
|
||||
|
||||
void release()
|
||||
{
|
||||
_block.release();
|
||||
}
|
||||
|
||||
|
||||
/** Release any thread waiting on the queue, even if the queue is empty. */
|
||||
void release();
|
||||
|
||||
/** Take a SceneView from the queue. Can return 0 if release() is called when the queue is empty. */
|
||||
osgUtil::SceneView* takeFront();
|
||||
|
||||
|
||||
/** Add a SceneView object to the back of the queue. */
|
||||
void add(osgUtil::SceneView* sv);
|
||||
};
|
||||
|
||||
|
@ -289,34 +289,53 @@ void ARBQuerySupport::checkQuery(osg::Stats* stats, osg::State* state,
|
||||
// ThreadSafeQueue
|
||||
|
||||
Renderer::ThreadSafeQueue::ThreadSafeQueue()
|
||||
: _isReleased(false)
|
||||
{
|
||||
_block.set(false);
|
||||
}
|
||||
|
||||
Renderer::ThreadSafeQueue::~ThreadSafeQueue()
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer::ThreadSafeQueue::release()
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
_isReleased = true;
|
||||
_cond.broadcast();
|
||||
}
|
||||
|
||||
osgUtil::SceneView* Renderer::ThreadSafeQueue::takeFront()
|
||||
{
|
||||
if (_queue.empty()) _block.block();
|
||||
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
if (_queue.empty()) return 0;
|
||||
|
||||
osgUtil::SceneView* front = _queue.front();
|
||||
_queue.pop_front();
|
||||
|
||||
if (_queue.empty()) _block.set(false);
|
||||
|
||||
return front;
|
||||
// Loop in case there are spurious wakeups from the condition wait.
|
||||
while (true)
|
||||
{
|
||||
// If the queue has been released but nothing is enqueued,
|
||||
// just return. This prevents a deadlock when threading is
|
||||
// restarted.
|
||||
if (_isReleased)
|
||||
{
|
||||
if (!_queue.empty())
|
||||
{
|
||||
osgUtil::SceneView* front = _queue.front();
|
||||
_queue.pop_front();
|
||||
if (_queue.empty())
|
||||
_isReleased = false;
|
||||
return front;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
_cond.wait(&_mutex);
|
||||
}
|
||||
return 0; // Can't happen
|
||||
}
|
||||
|
||||
void Renderer::ThreadSafeQueue::add(osgUtil::SceneView* sv)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
_queue.push_back(sv);
|
||||
_block.set(true);
|
||||
_isReleased = true;
|
||||
_cond.broadcast();
|
||||
}
|
||||
|
||||
static OpenThreads::Mutex s_drawSerializerMutex;
|
||||
|
Loading…
Reference in New Issue
Block a user