use threadsafe lazy construction of the tree

use c++11 memory model to fix the Double-Checked Locking
This commit is contained in:
Sébastien Loriot 2020-04-22 11:00:49 +02:00
parent f0db5488b8
commit 969fe84181
1 changed files with 33 additions and 6 deletions

View File

@ -98,13 +98,15 @@ class Side_of_triangle_mesh
//members //members
typename GeomTraits::Construct_ray_3 ray_functor; typename GeomTraits::Construct_ray_3 ray_functor;
typename GeomTraits::Construct_vector_3 vector_functor; typename GeomTraits::Construct_vector_3 vector_functor;
mutable const AABB_tree_* tree_ptr;
const TriangleMesh* tm_ptr; const TriangleMesh* tm_ptr;
boost::optional<VertexPointMap> opt_vpm; boost::optional<VertexPointMap> opt_vpm;
bool own_tree; bool own_tree;
CGAL::Bbox_3 box; CGAL::Bbox_3 box;
#ifdef CGAL_HAS_THREADS #ifdef CGAL_HAS_THREADS
mutable CGAL_MUTEX tree_mutex; mutable CGAL_MUTEX tree_mutex;
mutable std::atomic<const AABB_tree_*> atomic_tree_ptr;
#else
mutable const AABB_tree_* tree_ptr;
#endif #endif
public: public:
@ -129,10 +131,14 @@ public:
const GeomTraits& gt=GeomTraits()) const GeomTraits& gt=GeomTraits())
: ray_functor(gt.construct_ray_3_object()) : ray_functor(gt.construct_ray_3_object())
, vector_functor(gt.construct_vector_3_object()) , vector_functor(gt.construct_vector_3_object())
, tree_ptr(nullptr)
, tm_ptr(&tmesh) , tm_ptr(&tmesh)
, opt_vpm(vpmap) , opt_vpm(vpmap)
, own_tree(true) , own_tree(true)
#ifdef CGAL_HAS_THREADS
, atomic_tree_ptr(nullptr)
#else
, tree_ptr(nullptr)
#endif
{ {
CGAL_assertion(CGAL::is_triangle_mesh(tmesh)); CGAL_assertion(CGAL::is_triangle_mesh(tmesh));
CGAL_assertion(CGAL::is_closed(tmesh)); CGAL_assertion(CGAL::is_closed(tmesh));
@ -165,16 +171,24 @@ public:
const GeomTraits& gt = GeomTraits()) const GeomTraits& gt = GeomTraits())
: ray_functor(gt.construct_ray_3_object()) : ray_functor(gt.construct_ray_3_object())
, vector_functor(gt.construct_vector_3_object()) , vector_functor(gt.construct_vector_3_object())
, tree_ptr(&tree)
, own_tree(false) , own_tree(false)
#ifdef CGAL_HAS_THREADS
, atomic_tree_ptr(&tree)
#else
, tree_ptr(&tree)
#endif
{ {
box = tree.bbox(); box = tree.bbox();
} }
~Side_of_triangle_mesh() ~Side_of_triangle_mesh()
{ {
if (own_tree && tree_ptr!=nullptr) if (own_tree)
delete tree_ptr; #ifdef CGAL_HAS_THREADS
delete atomic_tree_ptr.load();
#else
delete tree_ptr.get();
#endif
} }
public: public:
@ -200,11 +214,16 @@ public:
} }
else else
{ {
#ifdef CGAL_HAS_THREADS
AABB_tree_* tree_ptr =
const_cast<AABB_tree_*>(atomic_tree_ptr.load(std::memory_order_acquire));
#endif
// Lazily build the tree only when needed // Lazily build the tree only when needed
if (tree_ptr==nullptr) if (tree_ptr==nullptr)
{ {
#ifdef CGAL_HAS_THREADS #ifdef CGAL_HAS_THREADS
CGAL_SCOPED_LOCK(tree_mutex); CGAL_SCOPED_LOCK(tree_mutex);
tree_ptr = const_cast<AABB_tree_*>(atomic_tree_ptr.load(std::memory_order_relaxed));
#endif #endif
CGAL_assertion(tm_ptr != nullptr && opt_vpm!=boost::none); CGAL_assertion(tm_ptr != nullptr && opt_vpm!=boost::none);
if (tree_ptr==nullptr) if (tree_ptr==nullptr)
@ -213,11 +232,19 @@ public:
faces(*tm_ptr).second, faces(*tm_ptr).second,
*tm_ptr, *opt_vpm); *tm_ptr, *opt_vpm);
const_cast<AABB_tree_*>(tree_ptr)->build(); const_cast<AABB_tree_*>(tree_ptr)->build();
#ifdef CGAL_HAS_THREADS
CGAL_SCOPED_LOCK(tree_mutex);
atomic_tree_ptr.store(tree_ptr, std::memory_order_release);
#endif
} }
} }
#ifdef CGAL_HAS_THREADS
return internal::Point_inside_vertical_ray_cast<GeomTraits, AABB_tree>()(
point, *atomic_tree_ptr.load(), ray_functor, vector_functor);
#else
return internal::Point_inside_vertical_ray_cast<GeomTraits, AABB_tree>()( return internal::Point_inside_vertical_ray_cast<GeomTraits, AABB_tree>()(
point, *tree_ptr, ray_functor, vector_functor); point, *tree_ptr, ray_functor, vector_functor);
#endif
} }
} }