From f13dd3d75d4b2f1fe9783db34f93cc1b4ed92788 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 31 Aug 2012 16:00:55 +0000 Subject: [PATCH] Added a fix for a multi-threading bug that occured when TerrainTiles were accessed via the Terrain::_updateTerrainTileSet that were being deleted at the same time by the DatabasePager thread. --- src/osgTerrain/Terrain.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/osgTerrain/Terrain.cpp b/src/osgTerrain/Terrain.cpp index e77f575a8..ea40ef6e9 100644 --- a/src/osgTerrain/Terrain.cpp +++ b/src/osgTerrain/Terrain.cpp @@ -97,7 +97,17 @@ void Terrain::traverse(osg::NodeVisitor& nv) TerrainTileList tiles; { OpenThreads::ScopedLock lock(_mutex); - std::copy(_updateTerrainTileSet.begin(), _updateTerrainTileSet.end(), std::back_inserter(tiles)); + for(TerrainTileSet::iterator itr = _updateTerrainTileSet.begin(); itr !=_updateTerrainTileSet.end(); ++itr) + { + // take a reference first to make sure that the referenceCount can be safely read without another thread decrementing it to zero. + (*itr)->ref(); + + // only if referenceCount is 2 or more indicating there is still a reference held elsewhere is it safe to add it to list of tiles to be updated + if ((*itr)->referenceCount()>1) tiles.push_back(*itr); + + // use unref_nodelete to avoid any issues when the *itr TerrainTile has been deleted by another thread while this for loop has been running. + (*itr)->unref_nodelete(); + } _updateTerrainTileSet.clear(); }