Corrected a rare race condition.

The few bad facets that are created during the "cell refinement" step are treated immediately inside the thread which created them.
This commit is contained in:
Clément Jamin 2012-03-29 15:05:28 +00:00
parent 4fdf647428
commit a520f3cbf0
20 changed files with 510 additions and 403 deletions

View File

@ -26,6 +26,8 @@
#endif
#ifdef CONCURRENT_MESH_3
#include <algorithm>
#include <tbb/tbb.h>
#include <CGAL/hilbert_sort.h>
@ -38,6 +40,9 @@
#include <CGAL/Profile_counter.h>
#endif
// CJTODO TEMP TEST
extern bool g_is_set_cell_active;
// CJTODO TEMP: not thread-safe => move it to Mesher_3
extern CGAL::Bbox_3 g_bbox;
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
@ -52,9 +57,13 @@ namespace CGAL {
enum Mesher_level_conflict_status {
NO_CONFLICT = 0,
CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED,
CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED
CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
, ELEMENT_WAS_A_ZOMBIE
#endif
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
, COULD_NOT_LOCK_ZONE
, COULD_NOT_LOCK_ELEMENT
#endif
};
@ -94,6 +103,15 @@ struct Null_mesher_level {
return false;
}
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
void add_to_TLS_lists(bool) {}
void splice_local_lists() {}
template <typename Mesh_visitor>
void before_next_element_refinement_in_superior(Mesh_visitor visitor) {}
void before_next_element_refinement() {}
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
std::string debug_info_class_name_impl() const
{
return "Null_mesher_level";
@ -237,7 +255,7 @@ public:
}
/** Retrieves the next element that could be refined. */
Element get_next_element()
Element get_next_element() const
{
return derived().get_next_element_impl();
}
@ -253,6 +271,71 @@ public:
{
return derived().circumcenter_impl(e);
}
void add_to_TLS_lists(bool add)
{
derived().add_to_TLS_lists_impl(add);
}
void splice_local_lists()
{
derived().splice_local_lists_impl();
}
bool no_longer_local_element_to_refine()
{
return derived().no_longer_local_element_to_refine_impl();
}
Element get_next_local_element()
{
return derived().get_next_local_element_impl();
}
void pop_next_local_element()
{
derived().pop_next_local_element_impl();
}
template <typename Mesh_visitor>
void treat_local_refinement_queue(Mesh_visitor visitor)
{
// We treat the elements of the local (TLS) refinement queue
while (no_longer_local_element_to_refine() == false)
{
typedef typename Derived::Container::Element Container_element;
Container_element ce = derived().get_next_local_raw_element_impl().second;
const Mesher_level_conflict_status status =
try_lock_and_refine_element(ce, visitor);
switch (status)
{
case NO_CONFLICT:
case CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED:
case ELEMENT_WAS_A_ZOMBIE:
pop_next_local_element();
break;
case COULD_NOT_LOCK_ZONE:
//tbb::this_tbb_thread::yield();
break;
}
}
}
template <typename Mesh_visitor>
void before_next_element_refinement_in_superior(Mesh_visitor visitor)
{
derived().before_next_element_refinement_in_superior_impl(visitor);
}
template <typename Mesh_visitor>
void before_next_element_refinement(Mesh_visitor visitor)
{
derived().before_next_element_refinement_impl();
previous_level.before_next_element_refinement_in_superior(
visitor.previous_level());
}
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
/** Gives the point that should be inserted to refine the element \c e */
@ -377,7 +460,11 @@ public:
{
previous_level.refine(visitor.previous_level());
if(! no_longer_element_to_refine() )
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
process_a_batch_of_elements(visitor);
#else
process_one_element(visitor);
#endif
}
}
@ -422,100 +509,6 @@ public:
return e.first;
}
bool try_lock_cells_from_element(const Cell_handle &e) const
{
return e->try_lock();
}
bool try_lock_cells_from_element(const Facet &e) const
{
return e.first->try_lock();
/*if (e.first->try_lock())
{
Facet mf = derived().triangulation_ref_impl().mirror_facet(e);
if (!mf.first->try_lock())
{
e.first->unlock();
return false;
}
else
{
return true;
}
}
else
{
return true;
}*/
}
template< typename Elt >
bool try_lock_element(const Elt &element, int lock_radius = 0)
{
bool success = true;
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
// Lock the element area on the grid
Vertex_handle vertices[4];
get_valid_vertices_of_element(element, vertices);
for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex)
{
const Vertex_handle null_vertex;
Vertex_handle vh = vertices[iVertex];
if (vh != null_vertex)
{
success = g_lock_grid.try_lock(vh->point(), lock_radius).first;
}
}
# elif defined(CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK)
success = try_lock_cells_from_element(element);
# endif
return success;
}
// Spin while not successful
template< typename Elt >
void lock_element(const Elt &element)
{
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
// Lock the element area on the grid
Vertex_handle vertices[4];
get_valid_vertices_of_element(element, vertices);
for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex)
{
const Vertex_handle null_vertex;
Vertex_handle vh = vertices[iVertex];
if (vh != null_vertex)
{
std::pair<bool, int> r = g_lock_grid.try_lock(vh->point());
bool success = r.first;
while( !success )
{
// Active wait
tbb::this_tbb_thread::yield();
success = g_lock_grid.try_lock(r.second);
}
}
}
# elif defined(CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK)
/*Cell_handle ch = get_cell_from_element(element);
bool success = ch->try_lock();
while( !success )
{
// Active wait
tbb::this_tbb_thread::yield();
success = ch->try_lock();
}*/
bool success = try_lock_cells_from_element(ch);
while( !success )
{
// Active wait
tbb::this_tbb_thread::yield();
success = try_lock_cells_from_element(ch);
}
# endif
}
void unlock_all_thread_local_elements()
{
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
@ -541,7 +534,6 @@ public:
template <class Mesh_visitor>
void process_a_batch_of_elements(Mesh_visitor visitor)
{
typedef typename Derived::Container::Element Container_element;
typedef typename Derived::Container::Quality Container_quality;
@ -553,12 +545,7 @@ public:
circumcenters.reserve(ELEMENT_BATCH_SIZE);
std::vector<std::ptrdiff_t> indices;
indices.reserve(ELEMENT_BATCH_SIZE);
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
static Profile_branch_counter_3 bcounter(
std::string("early withdrawals / late withdrawals / successes [") + debug_info_class_name() + "]");
# endif
/*int batch_size = ELEMENT_BATCH_SIZE;
if (debug_info_class_name() == "Refine_facets_3")
batch_size = 1;*/
@ -588,7 +575,7 @@ public:
// Search_traits(&(circumcenters[0])) );
//hilbert_sort( indices.begin(), indices.end(), Hilbert_sort_median_policy(),
// Search_traits(&(circumcenters[0])) );
std::random_shuffle(indices.begin(), indices.end());
/*for( size_t i = 0 ; i < iElt ; ++i)
{
@ -599,7 +586,7 @@ public:
{
const Mesher_level_conflict_status result
= try_to_refine_element(derived().extract_element_from_container_value(e),
visitor);
visitor);
if (result == CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED)
derived().insert_raw_element(raw_elements[i]);
}
@ -612,111 +599,62 @@ public:
// CJTODO: TEST
if (iElt > 20)
{
derived().addToTLSLists(true);
//g_is_set_cell_active = false;
previous_level.add_to_TLS_lists(true);
add_to_TLS_lists(true);
tbb::parallel_for(
tbb::blocked_range<size_t>( 0, iElt, 30 ),
tbb::blocked_range<size_t>( 0, iElt, MESH_3_REFINEMENT_GRAINSIZE ),
[&] (const tbb::blocked_range<size_t>& r)
{
for( size_t i = r.begin() ; i != r.end() ; )
{
int index = indices[i];
before_next_element_refinement(visitor);
Derived &derivd = derived();
//Container_element ce = raw_elements[index].second;
std::ptrdiff_t index = indices[i];
Container_element ce = container_elements[index];
if( !derivd.is_zombie(ce) )
{
//static tbb::queuing_mutex mutex;
//tbb::queuing_mutex::scoped_lock lock(mutex);
const Mesher_level_conflict_status status =
try_lock_and_refine_element(ce, visitor);
// Lock the element area on the grid
Element element = derivd.extract_element_from_container_value(ce);
bool locked = try_lock_element(element, FIRST_GRID_LOCK_RADIUS);
if( locked )
{
// Test it again as it may have changed in the meantime
if( !derivd.is_zombie(ce) )
{
//Global_mutex_type::scoped_lock lock;
//if( lock.try_acquire(g_global_mutex) )
//{
const Mesher_level_conflict_status result
= try_to_refine_element(element, visitor);
//lock.release();
if (result == CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED)
{
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
++bcounter; // It's not an withdrawal
# endif
// We try it again right now!
//CJTODO : faire une boucle pour reessayer tout de suite?
}
else if (result == COULD_NOT_LOCK_ZONE)
{
// Swap indices[i] and indices[i+1]
if (i+1 != r.end())
{
ptrdiff_t tmp = indices[i+1];
indices[i+1] = indices[i];
indices[i] = tmp;
}
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
bcounter.increment_branch_1(); // THIS is a late withdrawal!
# endif
}
else
{
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
++bcounter;
# endif
++i;
}
//}
}
else
{
++i;
}
// Unlock
unlock_all_thread_local_elements();
}
// else, we try it again
else
{
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
bcounter.increment_branch_2(); // THIS is an early withdrawal!
# endif
// Unlock
unlock_all_thread_local_elements();
tbb::this_tbb_thread::yield();
}
}
else
switch (status)
{
++i;
case NO_CONFLICT:
case CONFLICT_AND_ELEMENT_SHOULD_BE_DROPPED:
case ELEMENT_WAS_A_ZOMBIE:
++i;
break;
case COULD_NOT_LOCK_ZONE:
// Swap indices[i] and indices[i+1]
/*if (i+1 != r.end())
{
ptrdiff_t tmp = indices[i+1];
indices[i+1] = indices[i];
indices[i] = tmp;
}*/
// CJTODO: TEST THAT
// Swap indices[i] and indices[last]
ptrdiff_t tmp = indices[r.end() - 1];
indices[r.end() - 1] = indices[i];
indices[i] = tmp;
break;
}
}
}
);
derived().spliceLocalLists();
derived().addToTLSLists(false);
# ifdef CGAL_CONCURRENT_MESH_3_VERBOSE
std::cerr << " batch done." << std::endl;
# endif
splice_local_lists();
//previous_level.splice_local_lists(); // useless
previous_level.add_to_TLS_lists(false);
add_to_TLS_lists(false);
//g_is_set_cell_active = true;
}
// Go sequential
else
{
for (int i = 0 ; i < iElt ; )
{
int index = indices[i];
std::ptrdiff_t index = indices[i];
Derived &derivd = derived();
//Container_element ce = raw_elements[index].second;
@ -742,6 +680,10 @@ public:
unlock_all_thread_local_elements();
}
}
# ifdef CGAL_CONCURRENT_MESH_3_VERBOSE
std::cerr << " batch done." << std::endl;
# endif
}
/**
@ -852,6 +794,86 @@ public:
return result;
}
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
template <typename Container_element, typename Mesh_visitor>
Mesher_level_conflict_status
try_lock_and_refine_element(const Container_element &ce, Mesh_visitor visitor)
{
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
static Profile_branch_counter_3 bcounter(
std::string("early withdrawals / late withdrawals / successes [") + debug_info_class_name() + "]");
# endif
Mesher_level_conflict_status result;
Derived &derivd = derived();
if( !derivd.is_zombie(ce) )
{
// Lock the element area on the grid
Element element = derivd.extract_element_from_container_value(ce);
bool locked = triangulation().try_lock_element(
element, MESH_3_FIRST_GRID_LOCK_RADIUS);
if( locked )
{
// Test it again as it may have changed in the meantime
if( !derivd.is_zombie(ce) )
{
result = try_to_refine_element(element, visitor);
//lock.release();
if (result == CONFLICT_BUT_ELEMENT_CAN_BE_RECONSIDERED)
{
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
++bcounter; // It's not a withdrawal
# endif
// We try it again right now!
}
else if (result == COULD_NOT_LOCK_ZONE)
{
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
bcounter.increment_branch_1(); // THIS is a late withdrawal!
# endif
}
else
{
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
++bcounter;
# endif
}
}
else
{
result = ELEMENT_WAS_A_ZOMBIE;
}
// Unlock
unlock_all_thread_local_elements();
}
// else, we try it again
else
{
# ifdef CGAL_CONCURRENT_MESH_3_PROFILING
bcounter.increment_branch_2(); // THIS is an early withdrawal!
# endif
// Unlock
unlock_all_thread_local_elements();
tbb::this_tbb_thread::yield();
result = COULD_NOT_LOCK_ELEMENT;
}
}
else
{
result = ELEMENT_WAS_A_ZOMBIE;
}
return result;
}
#endif
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
template <class Mesh_visitor>
@ -888,7 +910,7 @@ public:
while(! is_algorithm_done() )
{
if( previous_level.try_to_insert_one_point(visitor.previous_level()) )
return true;
return true;
if(! no_longer_element_to_refine() )
if( process_one_element(visitor) )
return true;

View File

@ -7,7 +7,6 @@
#include <CGAL/Mesh_triangulation_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Triangulation_lazy_ds_cell_base_3.h>
#include <CGAL/Mesh_3/Robust_intersection_traits_3.h>
#include <CGAL/Polyhedral_mesh_domain_3.h>
@ -71,23 +70,7 @@ typedef Wrapper<Kernel> Function
typedef CGAL::Mesh_3::Labeled_mesh_domain_3<Function_wrapper, Kernel> Function_mesh_domain;
// Triangulation
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
typedef CGAL::Kernel_traits<Polyhedral_mesh_domain>::Kernel PMDKernel;
typedef CGAL::details::Mesh_geom_traits_generator<PMDKernel>::type Geom_traits;
typedef CGAL::Triangulation_lazy_ds_cell_base_3<> DS_cell_base;
typedef CGAL::Triangulation_cell_base_with_circumcenter_3<
Geom_traits, DS_cell_base> Cell_base_with_cc;
typedef CGAL::Regular_triangulation_cell_base_3<
Geom_traits, Cell_base_with_cc> Regular_cell_base;
typedef CGAL::Mesh_triangulation_3<
Polyhedral_mesh_domain,
Kernel,
Geom_traits,
Regular_cell_base>::type Tr;
#else
typedef CGAL::Mesh_triangulation_3<Polyhedral_mesh_domain>::type Tr;
#endif
typedef CGAL::Mesh_triangulation_3<Polyhedral_mesh_domain>::type Tr;
// 3D complex
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr> C3t3;

View File

@ -34,13 +34,16 @@
#include <CGAL/Mesh_3/Locking_data_structures.h> // CJODO TEMP?
#include <CGAL/BBox_3.h>
// CJTODO TEMP TEST
bool g_is_set_cell_active = true;
Global_mutex_type g_global_mutex; // CJTODO: temporary
// CJTODO TEMP: not thread-safe => move it to Mesher_3
// Elephant.off => BBox (x,y,z): [ -0.358688, 0.356308 ], [ -0.498433, 0.49535 ], [ -0.298931, 0.298456 ]
CGAL::Bbox_3 g_bbox(-0.35, 0.35, -0.5, 0.5, -0.3, 0.3);
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
CGAL::Mesh_3::Refinement_grid_type g_lock_grid(g_bbox, LOCKING_GRID_NUM_CELLS_PER_AXIS);
CGAL::Mesh_3::Refinement_grid_type g_lock_grid(g_bbox, MESH_3_LOCKING_GRID_NUM_CELLS_PER_AXIS);
# elif defined(CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK)
# include <utility>
@ -62,13 +65,14 @@ Meshing_thread* cgal_code_mesh_3(const Polyhedron*,
const double tets_sizing,
const double tet_shape);
// CJTODO TEMP
/*Meshing_thread* cgal_code_mesh_3(const Image*,
#ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES
Meshing_thread* cgal_code_mesh_3(const Image*,
const double angle,
const double sizing,
const double approx,
const double tets_sizing,
const double tet_shape);*/
const double tet_shape);
#endif
#ifdef CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS
Meshing_thread* cgal_code_mesh_3(const Implicit_function_interface*,
@ -261,9 +265,9 @@ void Mesh_3_plugin::mesh_3()
angle, facet_sizing, approx,
tet_sizing, radius_edge);
}
// Image
// CJTODO TEMP
/*else if( NULL != image_item )
// Image
#ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES
else if( NULL != image_item )
{
const Image* pImage = image_item->image();
if( NULL == pImage )
@ -275,7 +279,9 @@ void Mesh_3_plugin::mesh_3()
thread = cgal_code_mesh_3(pImage,
angle, facet_sizing, approx,
tet_sizing, radius_edge);
}*/
}
#endif
// Function
#ifdef CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS
else if( NULL != function_item )

View File

@ -1,5 +1,6 @@
// CJTODO TEMP
/*#include "config.h"
#include "config.h"
#ifdef CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES
#include "C3t3_type.h"
#include "Scene_c3t3_item.h"
@ -35,4 +36,5 @@ Meshing_thread* cgal_code_mesh_3(const Image* pImage,
Mesh_function* p_mesh_function = new Mesh_function(p_new_item->c3t3(), p_domain, param);
return new Meshing_thread(p_mesh_function, p_new_item);
}
*/
#endif

View File

@ -190,7 +190,9 @@ launch()
// Ensure c3t3 is ok (usefull if process has been stop by the user)
mesher_->fix_c3t3();
#ifdef WIN32
QSound::play("Ding.wav"); // CJTODO TEMP
#endif
}

View File

@ -23,13 +23,16 @@
#include <CGAL/Mesh_3/Locking_data_structures.h> // CJODO TEMP?
#include <CGAL/BBox_3.h>
// CJTODO TEMP TEST
bool g_is_set_cell_active = true;
//Global_mutex_type g_global_mutex; // CJTODO: temporary
// CJTODO TEMP: not thread-safe => move it to Mesher_3
// Elephant.off => BBox (x,y,z): [ -0.358688, 0.356308 ], [ -0.498433, 0.49535 ], [ -0.298931, 0.298456 ]
CGAL::Bbox_3 g_bbox(-0.35, 0.35, -0.5, 0.5, -0.3, 0.3);
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
CGAL::Mesh_3::Refinement_grid_type g_lock_grid(g_bbox, LOCKING_GRID_NUM_CELLS_PER_AXIS);
CGAL::Mesh_3::Refinement_grid_type g_lock_grid(g_bbox, MESH_3_LOCKING_GRID_NUM_CELLS_PER_AXIS);
# elif defined(CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK)
# include <utility>

View File

@ -4,6 +4,7 @@
#ifdef CONCURRENT_MESH_3
// In case some code uses CGAL_PROFILE, it needs to be concurrent
#define CGAL_CONCURRENT_PROFILE
#define CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
#endif
#include <cmath>
@ -287,7 +288,7 @@
//#include <CGAL/Mesh_3/Triangle_accessor_primitive.h>
//#include <CGAL/Mesh_3/Triangulation_lazy_ds_cell_base_3.h>
//#include <CGAL/Mesh_3/utilities.h>
#include <CGAL/Mesh_cell_base_3.h>
//#include <CGAL/Mesh_cell_base_3.h>
#include <CGAL/Mesh_cell_criteria_3.h>
#include <CGAL/Mesh_constant_domain_field_3.h>
#include <CGAL/Mesh_criteria_3.h>

View File

@ -20,7 +20,8 @@
# define CGAL_POLYHEDRON_DEMO_USE_SURFACE_MESHER
#endif
#define CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS
//#define CGAL_MESH_3_DEMO_ACTIVATE_IMPLICIT_FUNCTIONS
//#define CGAL_MESH_3_DEMO_ACTIVATE_SEGMENTED_IMAGES
// ==========================================================================
// CONCURRENCY
@ -37,7 +38,7 @@
# define CGAL_MESH_3_CONCURRENT_REFINEMENT
// In case some code uses CGAL_PROFILE, it needs to be concurrent
# define CGAL_CONCURRENT_PROFILE
//# define CGAL_CONCURRENT_MESH_3_VERBOSE
# define CGAL_CONCURRENT_MESH_3_VERBOSE
// ==========================================================================
// Locking strategy
@ -46,10 +47,11 @@
# ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
//# define CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK
# define CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
# define CGAL_MESH_3_CONCURRENT_REFINEMENT_LOCK_ADJ_CELLS
//# define CGAL_MESH_3_CONCURRENT_REFINEMENT_LOCK_ADJ_CELLS
const int LOCKING_GRID_NUM_CELLS_PER_AXIS = 25;
const int FIRST_GRID_LOCK_RADIUS = 2;
const int MESH_3_LOCKING_GRID_NUM_CELLS_PER_AXIS = 30;
const int MESH_3_FIRST_GRID_LOCK_RADIUS = 2;
const int MESH_3_REFINEMENT_GRAINSIZE = 10;
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK
# include <tbb/recursive_mutex.h>
@ -58,7 +60,7 @@
# endif
// ==========================================================================
// CJTODO: temp
// CJTODO TEMP
// ==========================================================================
# include <tbb/tbb.h>
typedef tbb::recursive_mutex Global_mutex_type;
@ -68,7 +70,7 @@
// Concurrency Parameters
// ==========================================================================
const size_t ELEMENT_BATCH_SIZE = 3000;
const size_t ELEMENT_BATCH_SIZE = 30000;
// ==========================================================================
// Profiling

View File

@ -1527,11 +1527,18 @@ get_conflict_zone_topo_change(const Vertex_handle& vertex,
return conflict_cells;
// Find conflict zone
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
bool could_lock_zone = true;
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
tr_.find_conflicts(conflict_point,
cell,
CGAL::Emptyset_iterator(),
std::back_inserter(deleted_cells),
CGAL::Emptyset_iterator());
CGAL::Emptyset_iterator()
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
, could_lock_zone
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
);
// Compute union of conflict_point conflict zone and triangulation_vertex
// incident cells

View File

@ -84,9 +84,6 @@ public:
bool try_lock(int cell_index)
{
//if (cell_index == 0) // CJTODO TEMP
// return true;
bool ret = false;
// Already locked by this thread?
if (m_tls_grids.local()[cell_index])
@ -297,9 +294,6 @@ public:
bool try_lock(int cell_index)
{
//if (cell_index == 0) // CJTODO TEMP
// return true;
bool ret = false;
// Already locked by this thread?
if (m_tls_grids.local()[cell_index])
@ -460,8 +454,8 @@ protected:
TLS_locked_cells m_tls_locked_cells;
};
//typedef Simple_grid_locking_ds_with_mutex Refinement_grid_type;
typedef Simple_grid_locking_ds Refinement_grid_type;
typedef Simple_grid_locking_ds_with_mutex Refinement_grid_type;
//typedef Simple_grid_locking_ds Refinement_grid_type;
} //namespace Mesh_3

View File

@ -181,6 +181,20 @@ public:
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
template <class Mesh_visitor>
void process_a_batch_of_elements_impl(Mesh_visitor visitor);
Point circumcenter_impl(const Cell_handle& cell) const
{
return r_tr_.dual(cell);
}
template <typename Mesh_visitor>
void before_next_element_refinement_in_superior_impl(Mesh_visitor)
{
}
void before_next_element_refinement_impl()
{
}
#endif
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
@ -194,11 +208,6 @@ public:
{
return extract_element_from_container_value(Container_::get_next_element_impl());
}
Point circumcenter_impl(const Cell_handle& cell) const
{
return r_tr_.dual(cell);
};
#endif
// Gets the point to insert from the element to refine
@ -385,7 +394,7 @@ scan_triangulation_impl()
#ifdef CGAL_MESH_3_CONCURRENT_SCAN_TRIANGULATION
addToTLSLists(true);
add_to_TLS_lists(true);
/*
// WITH PARALLEL_FOR
WallClockTimer t2;
@ -414,9 +423,9 @@ scan_triangulation_impl()
treat_new_cell( c );
});
spliceLocalLists();
splice_local_lists();
//std::cerr << "Parallel_for - splice done: " << t2.elapsed() << " seconds." << std::endl;
addToTLSLists(false);
add_to_TLS_lists(false);
#else
for(Finite_cell_iterator cell_it = r_tr_.finite_cells_begin();
cell_it != r_tr_.finite_cells_end();

View File

@ -187,6 +187,24 @@ public:
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
template <class Mesh_visitor>
void process_a_batch_of_elements_impl(Mesh_visitor visitor);
Point circumcenter_impl(const Facet& facet) const
{
return get_facet_surface_center(facet);
}
template <typename Mesh_visitor>
void before_next_element_refinement_in_superior_impl(Mesh_visitor visitor)
{
// Before refining any cell, we refine the facets in the local refinement
// queue
this->treat_local_refinement_queue(visitor);
}
void before_next_element_refinement_impl()
{
}
#endif
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
@ -198,14 +216,20 @@ public:
Facet get_next_element_impl() const
{
return extract_element_from_container_value(Container_::get_next_element_impl());
return extract_element_from_container_value(
Container_::get_next_element_impl());
}
Point circumcenter_impl(const Facet& facet) const
# ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
Facet get_next_local_element_impl()
{
return get_facet_surface_center(facet);
};
return extract_element_from_container_value(
Container_::get_next_local_element_impl());
}
# endif
#endif
/// Gets the point to insert from the element to refine
Point refinement_point_impl(const Facet& facet) const
@ -547,7 +571,7 @@ scan_triangulation_impl()
#ifdef CGAL_MESH_3_CONCURRENT_SCAN_TRIANGULATION
addToTLSLists(true);
add_to_TLS_lists(true);
// PARALLEL_DO
tbb::parallel_do(r_tr_.finite_facets_begin(), r_tr_.finite_facets_end(),
[=]( const Facet &facet ) { // CJTODO: lambdas ok?
@ -555,8 +579,8 @@ scan_triangulation_impl()
Facet f = facet;
treat_new_facet( f );
});
spliceLocalLists();
addToTLSLists(false);
splice_local_lists();
add_to_TLS_lists(false);
#else
for(Finite_facet_iterator facet_it = r_tr_.finite_facets_begin();
@ -602,23 +626,7 @@ test_point_conflict_from_superior_impl(const Point& point, Zone& zone
if ( is_encroached_facet_refinable(*facet_it) )
{
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
// CJTODO TEMP: not very clean
Facet mirror = mirror_facet(*facet_it);
auto f = boost::make_tuple(
*facet_it, facet_it->first->get_erase_counter(),
mirror, mirror.first->get_erase_counter());
// Unlock all
unlock_all_thread_local_elements();
// CJTODO: what if it doesn's succeed???
if( try_lock_element(*facet_it) )
{
// CJTODO: what if it doesn's succeed???
if( !is_zombie(f) )
try_to_refine_element(*facet_it, visitor);
}
try_to_refine_element(*facet_it, visitor);
#else
insert_encroached_facet_in_queue(*facet_it);
#endif
@ -639,21 +647,7 @@ test_point_conflict_from_superior_impl(const Point& point, Zone& zone
if ( is_encroached_facet_refinable(*facet_it) )
{
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
// CJTODO TEMP: not very clean
Facet mirror = mirror_facet(*facet_it);
auto f = boost::make_tuple(
*facet_it, facet_it->first->get_erase_counter(),
mirror, mirror.first->get_erase_counter());
unlock_all_thread_local_elements();
// CJTODO: what if it doesn's succeed???
if( try_lock_element(*facet_it) )
{
// CJTODO: what if it doesn's succeed???
if( !is_zombie(f) )
try_to_refine_element(*facet_it, visitor);
}
try_to_refine_element(*facet_it, visitor);
#else
insert_encroached_facet_in_queue(*facet_it);
#endif

View File

@ -1015,11 +1015,19 @@ update_mesh(const Weighted_point& new_point,
internal_facets.reserve(64);
boundary_facets.reserve(64);
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
bool could_lock_zone = true;
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
tr_.find_conflicts(new_point,
old_vertex->cell(),
std::back_inserter(boundary_facets),
std::back_inserter(deleted_cells),
std::back_inserter(internal_facets));
std::back_inserter(internal_facets)
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
, could_lock_zone
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
);
// Get some datas to restore mesh
Boundary_facets_from_outside boundary_facets_from_outside =
@ -1167,11 +1175,19 @@ check_pre_star(const Pre_star& pre_star,
std::vector<Facet> boundary_facets;
boundary_facets.reserve(64);
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
bool could_lock_zone = true;
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
tr_.find_conflicts(wp,
vh->cell(),
std::back_inserter(boundary_facets),
CGAL::Emptyset_iterator(),
CGAL::Emptyset_iterator());
CGAL::Emptyset_iterator()
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
, could_lock_zone
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
);
const bool result = check_pre_star(pre_star,
boundary_facets.begin(),

View File

@ -49,18 +49,19 @@ namespace CGAL {
Map multimap;
Predicate test;
#ifdef CONCURRENT_MESH_3
typedef tbb::enumerable_thread_specific< std::vector<std::pair<Quality, Element> > > LocalList;
LocalList localList;
bool m_addToTLSLists;
typedef tbb::enumerable_thread_specific<
std::deque<std::pair<Quality, Element> > > LocalList;
LocalList m_local_lists;
bool m_add_to_TLS_lists;
#endif
public:
#ifdef CONCURRENT_MESH_3
explicit Filtered_multimap_container(bool addToTLSLists = false)
: m_addToTLSLists(addToTLSLists) {}
explicit Filtered_multimap_container(const Predicate &p, bool addToTLSLists=false)
: test(p), m_addToTLSLists(addToTLSLists) {}
explicit Filtered_multimap_container(bool add_to_TLS_lists = false)
: m_add_to_TLS_lists(add_to_TLS_lists) {}
explicit Filtered_multimap_container(const Predicate &p, bool add_to_TLS_lists=false)
: test(p), m_add_to_TLS_lists(add_to_TLS_lists) {}
#else
Filtered_multimap_container() {}
explicit Filtered_multimap_container(const Predicate &p)
@ -69,6 +70,9 @@ namespace CGAL {
bool no_longer_element_to_refine_impl()
{
#ifdef _DEBUG
size_t multimap_size = multimap.size();
#endif
bool is_empty = multimap.empty();
while( !is_empty && !test(multimap.begin()->second) )
{
@ -99,21 +103,67 @@ namespace CGAL {
}
#ifdef CONCURRENT_MESH_3
void addToTLSLists(bool add = true)
void add_to_TLS_lists_impl(bool add = true)
{
m_addToTLSLists = add;
m_add_to_TLS_lists = add;
}
void spliceLocalLists()
void splice_local_lists_impl()
{
for( LocalList::iterator it_list = localList.begin() ;
it_list != localList.end() ;
for( LocalList::iterator it_list = m_local_lists.begin() ;
it_list != m_local_lists.end() ;
++it_list )
{
#ifdef _DEBUG
size_t multimap_size = multimap.size();
size_t local_list_size = it_list->size();
#endif
multimap.insert(it_list->begin(), it_list->end());
it_list->clear();
}
}
bool no_longer_local_element_to_refine_impl()
{
bool is_empty = m_local_lists.local().empty();
while( !is_empty && !test(m_local_lists.local().front().second) )
{
pop_next_local_element_impl();
is_empty = m_local_lists.local().empty();
}
return is_empty;
}
// Warning: no_longer_local_element_to_refine_impl must have been called
// just before calling get_next_local_element_impl
// (successive calls to "get_next_local_element_impl" are not allowed)
Element get_next_local_element_impl()
{
CGAL_assertion(!m_local_lists.local().empty());
// CJTODO BUG: add this? It shouldn't be necessary as user
// is supposed to call "no_longer_element_to_refine_impl" first
/*while( !test(multimap.front()) )
{
multimap.pop_front();
}*/
return m_local_lists.local().front().second;
}
// Warning: no_longer_local_element_to_refine_impl must have been called
// just before calling get_next_local_raw_element_impl
// (successive calls to "get_next_local_raw_element_impl" are not allowed)
value_type get_next_local_raw_element_impl()
{
CGAL_assertion(!m_local_lists.local().empty());
return m_local_lists.local().front();
}
void pop_next_local_element_impl()
{
// Erase last element
m_local_lists.local().pop_front();
}
#endif
void pop_next_element_impl()
@ -138,8 +188,8 @@ namespace CGAL {
}
// Warning: no_longer_element_to_refine_impl must have been called
// just before calling get_next_element_impl
// (successive calls to "get_next_element_impl" are not allowed)
// just before calling get_next_raw_element_impl
// (successive calls to "get_next_raw_element_impl" are not allowed)
value_type get_next_raw_element_impl()
{
CGAL_assertion(!multimap.empty());
@ -149,8 +199,8 @@ namespace CGAL {
void insert_raw_element(const value_type &re)
{
#ifdef CONCURRENT_MESH_3
if (m_addToTLSLists)
localList.local().push_back(re);
if (m_add_to_TLS_lists)
m_local_lists.local().push_back(re);
else
multimap.insert(re);
#else

View File

@ -1,4 +1,4 @@
// Copyright (c) 1999-2005 INRIA Sophia-Antipolis (France).
// Copyright (c) 2012 INRIA Sophia-Antipolis (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
@ -64,50 +64,9 @@ public:
bool success = true;
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
// Lock the element area on the grid
for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex)
{
Vertex_handle vh = vertex(iVertex);
//if (vh != infinite_vertex()) // CJTODO: à tester?
std::pair<bool, int> r = g_lock_grid.try_lock(vh->point());
success = r.first;
}
# elif defined(CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK)
success = m_mutex.try_lock();
if (success)
g_tls_locked_cells.local().push_back(std::make_pair(this, m_erase_counter));
# endif
return success;
}
/*
bool try_lock(bool unlock_if_failure = false)
{
bool success = true;
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
int locked_vertices[4];
// Lock the element area on the grid
for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex)
{
Vertex_handle vh = vertex(iVertex);
//if (vh != infinite_vertex()) // CJTODO: à tester?
std::pair<bool, int> r = g_lock_grid.try_lock(vh->point());
success = r.first;
if (unlock_if_failure)
{
if (success)
{
locked_vertices[iVertex] = r.second;
}
else
{
// Unlock elements we locked
for (int i = 0 ; i < iVertex ; ++i)
g_lock_grid.unlock(locked_vertices[i]);
}
}
}
std::cerr << "Error: Triangulation_lazy_ds_cell_base_3::try_lock() "
"should not be called. Use Triangulation_3::try_lock_element() instead."
<< std::endl;
# elif defined(CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK)
success = m_mutex.try_lock();
@ -117,7 +76,6 @@ public:
return success;
}
*/
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK
void lock()
@ -130,24 +88,6 @@ public:
{
m_mutex.unlock();
}
#elif defined(CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING)
// CJTODO: Warning: this lock is not "atomic", it locks
// one vertex after the other
void lock()
{
// Active wait
while (!try_lock())
tbb::this_tbb_thread::yield();
}
void unlock()
{
for (int iVertex = 0 ; iVertex < 4 ; ++iVertex)
{
Vertex_handle vh = vertex(iVertex);
g_lock_grid.unlock(vh->point());
}
}
# endif
typedef tbb::atomic<unsigned int> Erase_counter_type;

View File

@ -519,6 +519,60 @@ public:
# endif // no CGAL_T3_STRUCTURAL_FILTERING_MAX_VISITED_CELLS
// LOCKS (CONCURRENCY)
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
bool try_lock_element(Cell_handle cell_handle, int lock_radius = 0) const
{
bool success = true;
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
// Lock the element area on the grid
for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex)
{
Vertex_handle vh = cell_handle->vertex(iVertex);
// We do not lock the infinite vertex
//if (!is_infinite(vh))
{
success = g_lock_grid.try_lock(vh->point(), lock_radius).first;
}
}
# elif defined(CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK)
success = cell_handle->try_lock();
# endif
return success;
}
bool try_lock_element(const Facet &facet, int lock_radius = 0) const
{
bool success = true;
# ifdef CGAL_MESH_3_LOCKING_STRATEGY_SIMPLE_GRID_LOCKING
// Lock the element area on the grid
Cell_handle cell = facet.first;
for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex)
{
if (iVertex != facet.second)
{
Vertex_handle vh = cell->vertex(iVertex);
// We do not lock the infinite vertex
//if (!is_infinite(vh))
{
success = g_lock_grid.try_lock(vh->point(), lock_radius).first;
}
}
}
# elif defined(CGAL_MESH_3_LOCKING_STRATEGY_CELL_LOCK)
success = facet.first->try_lock(); // CJTODO: we lock the cell => stupid?
# endif
return success;
}
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
protected:
Cell_handle
inexact_locate(const Point& p,
@ -864,7 +918,8 @@ protected:
template < class InputIterator >
bool infinite_vertex_in_range(InputIterator first, InputIterator beyond) const;
// - c is the current cell, which must be in conflict.
// - tester is the function object that tests if a cell is in conflict.
template <
@ -901,7 +956,7 @@ protected:
// CJTODO: useless?
if (p_could_lock_zone)
{
if (!d->try_lock())
if (!try_lock_element(d))
{
*p_could_lock_zone = false;
return it;
@ -911,14 +966,12 @@ protected:
// To store the bouldary cells, in case we need to rollback
// CJTODO: make it static TLS (for performance)
// CJTODO: useless car déjà fait dans Regular_tri_3::find_conflicts?
std::vector<Cell_handle> marked_cells;
#endif // CGAL_MESH_3_CONCURRENT_REFINEMENT
cell_stack.push(d);
d->tds_data().mark_in_conflict();
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
marked_cells.push_back(d);
#endif
*it.second++ = d;
@ -937,15 +990,9 @@ protected:
defined(CGAL_MESH_3_CONCURRENT_REFINEMENT_LOCK_ADJ_CELLS)
if (p_could_lock_zone)
{
if (!test->try_lock())
if (!try_lock_element(test))
{
*p_could_lock_zone = false;
// Rollback
// CJTODO: is it really necessary?
std::vector<Cell_handle>::iterator it_marked_cell = marked_cells.begin();
std::vector<Cell_handle>::iterator it_marked_cell_end = marked_cells.end();
for ( ; it_marked_cell != it_marked_cell_end ; ++it_marked_cell)
(*it_marked_cell)->tds_data().clear();
return it;
}
}
@ -965,15 +1012,9 @@ protected:
!defined(CGAL_MESH_3_CONCURRENT_REFINEMENT_LOCK_ADJ_CELLS)
if (p_could_lock_zone)
{
if (!test->try_lock())
if (!try_lock_element(test))
{
*p_could_lock_zone = false;
// Rollback
// CJTODO: is it really necessary?
std::vector<Cell_handle>::iterator it_marked_cell = marked_cells.begin();
std::vector<Cell_handle>::iterator it_marked_cell_end = marked_cells.end();
for ( ; it_marked_cell != it_marked_cell_end ; ++it_marked_cell)
(*it_marked_cell)->tds_data().clear();
// Unlock
return it;
}
@ -986,17 +1027,11 @@ protected:
cell_stack.push(test);
test->tds_data().mark_in_conflict();
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
marked_cells.push_back(test);
#endif
*it.second++ = test;
continue;
}
test->tds_data().mark_on_boundary();
#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
marked_cells.push_back(test);
#endif
}
*it.first++ = Facet(c, i);
}
@ -2056,11 +2091,9 @@ exact_locate(const Point & p, Locate_type & lt, int & li, int & lj,
{
// CJTODO: useless? already locked buy Mesher_level?
//c->lock(); // WARNING: not atomic! => DEADLOCKS?
if (!c->try_lock())
if (!try_lock_element(c))
{
*p_could_lock_zone = false;
// CJTODO: WHY DOES IT CRASH IF WE UNLOCK HERE??? (TEST IT)
//g_lock_grid.unlock_all_tls_locked_cells();
return Cell_handle();
}
}
@ -2129,11 +2162,9 @@ exact_locate(const Point & p, Locate_type & lt, int & li, int & lj,
{
//previous->unlock(); CJTODO: On en déverrouille TROP, non ?
//c->lock(); // WARNING: not atomic! => DEADLOCKS?
if (!c->try_lock())
if (!try_lock_element(c))
{
*p_could_lock_zone = false;
// CJTODO: WHY DOES IT CRASH IF WE UNLOCK HERE??? (TEST IT)
//g_lock_grid.unlock_all_tls_locked_cells();
return Cell_handle();
}
}

View File

@ -25,11 +25,19 @@
#include <CGAL/basic.h>
#include <CGAL/triangulation_assertions.h>
#include <CGAL/Triangulation_ds_cell_base_3.h>
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
# include <CGAL/Triangulation_lazy_ds_cell_base_3.h>
#else
# include <CGAL/Triangulation_ds_cell_base_3.h>
#endif
namespace CGAL {
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
template < typename GT, typename Cb = Triangulation_lazy_ds_cell_base_3<> >
#else
template < typename GT, typename Cb = Triangulation_ds_cell_base_3<> >
#endif
class Triangulation_cell_base_3
: public Cb
{

View File

@ -26,11 +26,19 @@
#include <CGAL/basic.h>
#include <CGAL/triangulation_assertions.h>
#include <CGAL/Triangulation_ds_cell_base_3.h>
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
# include <CGAL/Triangulation_lazy_ds_cell_base_3.h>
#else
# include <CGAL/Triangulation_ds_cell_base_3.h>
#endif
namespace CGAL {
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
template < typename GT, typename Cb = Triangulation_lazy_ds_cell_base_3<> >
#else
template < typename GT, typename Cb = Triangulation_ds_cell_base_3<> >
#endif
class Triangulation_cell_base_with_circumcenter_3
: public Cb
{

View File

@ -45,7 +45,11 @@
#include <CGAL/Compact_container.h>
#endif
#include <CGAL/Triangulation_ds_cell_base_3.h>
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
# include <CGAL/Triangulation_lazy_ds_cell_base_3.h>
#else
# include <CGAL/Triangulation_ds_cell_base_3.h>
#endif
#include <CGAL/Triangulation_ds_vertex_base_3.h>
#include <CGAL/Triangulation_simplex_3.h>
@ -66,7 +70,11 @@ namespace CGAL {
// TODO : noms : Vb != Vertex_base : clarifier.
template < class Vb = Triangulation_ds_vertex_base_3<>,
#ifdef CGAL_MESH_3_LAZY_REFINEMENT_QUEUE
class Cb = Triangulation_lazy_ds_cell_base_3<> >
#else
class Cb = Triangulation_ds_cell_base_3<> >
#endif
class Triangulation_data_structure_3
: public Triangulation_utils_3
{

View File

@ -23,6 +23,14 @@
#include <CGAL/basic.h>
#include <CGAL/internal/Dummy_tds_3.h>
// CJTODO TEMP TEST
#ifdef CONCURRENT_MESH_3
//# ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
//# include <tbb/atomic.h>
//# endif
extern bool g_is_set_cell_active;
#endif
namespace CGAL {
template < typename TDS = void >
@ -46,7 +54,15 @@ public:
{ return _c; }
void set_cell(Cell_handle c)
{ _c = c; }
{
// CJTODO TEMP TEST
#ifdef CONCURRENT_MESH_3
if (g_is_set_cell_active)
_c = c;
#else
_c = c;
#endif
}
// the following trivial is_valid allows
// the user of derived cell base classes
@ -63,7 +79,12 @@ public:
{ return _c.for_compact_container(); }
private:
// CJTODO TEMP
//#ifdef CGAL_MESH_3_CONCURRENT_REFINEMENT
// tbb::atomic<Cell_handle> _c;
//#else
Cell_handle _c;
//#endif
};
template < class TDS >