From 440a654a5856ac657c6f20f0ec2ca18467eb818c Mon Sep 17 00:00:00 2001 From: Clement Jamin Date: Wed, 5 Jun 2013 17:23:19 +0200 Subject: [PATCH] Added a concurrency-safe version of DT3::find_conflicts + better doc --- .../CGAL/Delaunay_triangulation_3.h | 25 +++++++--- .../CGAL/Regular_triangulation_3.h | 28 +++++------ .../Triangulation_3/CGAL/Triangulation_3.h | 12 ++--- .../doc/Triangulation_3/Triangulation_3.txt | 5 ++ .../include/CGAL/Delaunay_triangulation_3.h | 13 +++-- .../include/CGAL/Regular_triangulation_3.h | 17 ++++--- .../include/CGAL/Triangulation_3.h | 47 +++++++++---------- 7 files changed, 83 insertions(+), 64 deletions(-) diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Delaunay_triangulation_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Delaunay_triangulation_3.h index a2606cafd68..21e0670b85c 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Delaunay_triangulation_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Delaunay_triangulation_3.h @@ -148,9 +148,9 @@ The optional argument `start` is used as a starting place for the search. The optional argument `could_lock_zone` is used by the concurrency-safe version of the triangulation. When the pointer is not null, the insertion will -try to lock vertices/cells before modifying them. If it succeeds, *could_lock_zone +try to lock cells before modifying them. If it succeeds, *could_lock_zone is true, otherwise it is false and the return value is Vertex_handle() -(the point is not inserted). In any case, the locked vertices are not unlocked by the +(the point is not inserted). In any case, the locked cells are not unlocked by the function, leaving this choice to the user. */ Vertex_handle insert(const Point & p, @@ -259,9 +259,9 @@ void remove(Vertex_handle v); Removes the vertex `v` from the triangulation. This function is concurrency-safe if the triangulation is concurrency-safe. The removal will -try to lock vertices/cells before deleting/modifying them. If it succeeds, *could_lock_zone +try to lock cells before deleting/modifying them. If it succeeds, *could_lock_zone is true, otherwise it is false (and the point is not removed). In any case, -the locked vertices are not unlocked by the function, leaving this choice to the user. +the locked cells are not unlocked by the function, leaving this choice to the user. This function will try to remove `v` only if the removal does not decrease the dimension. If the removal would decrease dimension, the function returns false @@ -403,6 +403,12 @@ respectively in the output iterators: (resp. edges) `(t, i)` where the cell (resp. facet) `t` is in conflict, but `t->neighbor(i)` is not. +- `could_lock_zone`: The optional argument `could_lock_zone` is used by the concurrency-safe + version of the triangulation. When the pointer is not null, the algorithm will + try to lock all the cells of the conflict zone. If it succeeds, *could_lock_zone + is true, otherwise it is false (and the returned conflict zone is only partial). In any case, + the locked cells are not unlocked by the function, leaving this choice to the user. + This function can be used in conjunction with `insert_in_hole()` in order to decide the insertion of a point after seeing which elements of the triangulation are affected. @@ -415,7 +421,7 @@ class OutputIteratorCells> std::pair find_conflicts(Point p, Cell_handle c, OutputIteratorBoundaryFacets bfit, -OutputIteratorCells cit); +OutputIteratorCells cit, bool *could_lock_zone = NULL); /*! Same as the other `find_conflicts()` function, except that it also @@ -432,6 +438,12 @@ conflict, but `t->neighbor(i)` is not. - `ifit`: the facets (resp. edges) inside the hole, that is, delimiting two cells (resp facets) in conflict. +- `could_lock_zone`: The optional argument `could_lock_zone` is used by the concurrency-safe + version of the triangulation. When the pointer is not null, the algorithm will + try to lock all the cells of the conflict zone. If it succeeds, *could_lock_zone + is true, otherwise it is false (and the returned conflict zone is only partial). In any case, + the locked cells are not unlocked by the function, leaving this choice to the user. + Returns the `Triple` composed of the resulting output iterators. \pre `dt`.`dimension()` \f$ \geq2\f$, and `c` is in conflict with `p`. @@ -445,7 +457,8 @@ OutputIteratorInternalFacets> find_conflicts(Point p, Cell_handle c, OutputIteratorBoundaryFacets bfit, OutputIteratorCells cit, -OutputIteratorInternalFacets ifit); +OutputIteratorInternalFacets ifit, +bool *could_lock_zone = NULL); /*! This function is renamed `vertices_on_conflict_zone_boundary` since CGAL-3.8. diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_3.h index a9ebf96af5b..34adedb5cf0 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Regular_triangulation_3.h @@ -132,9 +132,9 @@ constructed handle. The optional argument `could_lock_zone` is used by the concurrency-safe version of the triangulation. When the pointer is not null, the insertion will -try to lock vertices/cells before modifying them. If it succeeds, *could_lock_zone +try to lock cells before modifying them. If it succeeds, *could_lock_zone is true, otherwise it is false (and the point is not inserted). In any case, -the locked vertices are not unlocked by the function, leaving this choice to the user. +the locked cells are not unlocked by the function, leaving this choice to the user. */ Vertex_handle insert(const Weighted_point & p, Cell_handle start = Cell_handle(), bool *could_lock_zone = NULL); @@ -239,9 +239,9 @@ void remove(Vertex_handle v); Removes the vertex `v` from the triangulation. This function is concurrency-safe if the triangulation is concurrency-safe. The removal will -try to lock vertices/cells before deleting/modifying them. If it succeeds, *could_lock_zone +try to lock cells before deleting/modifying them. If it succeeds, *could_lock_zone is true, otherwise it is false (and the point is not removed). In any case, -the locked vertices are not unlocked by the function, leaving this choice to the user. +the locked cells are not unlocked by the function, leaving this choice to the user. This function will try to remove `v` only if the removal does not decrease the dimension. @@ -425,17 +425,17 @@ Compute the conflicts with `p`. @param cit The cells (resp. facets) in conflict with `p`. @param bfit The facets (resp. edges) on the boundary of the conflict zone, that is, the facets (resp.\ edges) `(t, i)` where the cell (resp.. facet) `t` is in conflict, but `t->neighbor(i)` is not. @param ifit The facets (resp.\ edges) inside the conflict zone, that facets incident to two cells (resp.\ facets) in conflict. -@param could_lock_zone The optional argument `could_lock_zone` is used by the concurrency-safe +@param could_lock_zone The optional argument `could_lock_zone` is used by the concurrency-safe version of the triangulation. When the pointer is not null, the algorithm will - try to lock vertices of the conflict zone. If it succeeds, *could_lock_zone + try to lock all the cells of the conflict zone. If it succeeds, *could_lock_zone is true, otherwise it is false (and the returned conflict zone is only partial). In any case, - the locked vertices are not unlocked by the function, leaving this choice to the user. -@param p_this_facet_must_be_in_the_cz - If the optional argument `p_this_facet_must_be_in_the_cz` is not null, the algorithm will check + the locked cells are not unlocked by the function, leaving this choice to the user. +@param this_facet_must_be_in_the_cz + If the optional argument `this_facet_must_be_in_the_cz` is not null, the algorithm will check if this facet is in the conflict zone (it may be internal as well as boundary). -@param p_the_facet_is_in_its_cz - This argument must be not null if the previous `p_this_facet_must_be_in_the_cz` argument is not null. - The boolean value pointed by this pointer is set to true if *`p_this_facet_must_be_in_the_cz` is +@param the_facet_is_in_its_cz + This argument must be not null if the previous `this_facet_must_be_in_the_cz` argument is not null. + The boolean value pointed by this pointer is set to true if *`this_facet_must_be_in_the_cz` is among the internal or boundary facets of the conflict zone, and false otherwise. \pre The starting cell (resp.\ facet) `c` must be in conflict with `p`. @@ -456,8 +456,8 @@ OutputIteratorBoundaryFacets bfit, OutputIteratorCells cit, OutputIteratorInternalFacets ifit, bool *could_lock_zone = NULL, -const Facet *p_this_facet_must_be_in_the_cz = 0, -bool *p_the_facet_is_in_its_cz = 0); +const Facet *this_facet_must_be_in_the_cz = NULL, +bool *the_facet_is_in_its_cz = NULL); /*! This function is renamed `vertices_on_conflict_zone_boundary` since CGAL-3.8. diff --git a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h index d37f70ea54b..1ad1583516d 100644 --- a/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h +++ b/Triangulation_3/doc/Triangulation_3/CGAL/Triangulation_3.h @@ -208,7 +208,7 @@ typedef TriangulationDataStructure_3::Facet_circulator Facet_circulator; /*! Concurrency tag (from the TDS). */ -typedef TriangulationDataStructure_3::::Concurrency_tag Concurrency_tag; +typedef TriangulationDataStructure_3::Concurrency_tag Concurrency_tag; /// @} @@ -605,8 +605,8 @@ The optional argument `start` is used as a starting place for the search. The optional argument `could_lock_zone` is used by the concurrency-safe version of the triangulation. When the pointer is not null, the locate will -try to lock all the vertices along the walk. If it succeeds, *could_lock_zone -is true, otherwise it is false. In any case, the locked vertices are not +try to lock all the cells along the walk. If it succeeds, *could_lock_zone +is true, otherwise it is false. In any case, the locked cells are not unlocked by `locate`, leaving this choice to the user. */ Cell_handle @@ -644,8 +644,8 @@ The optional argument `start` is used as a starting place for the search. The optional argument `could_lock_zone` is used by the concurrency-safe version of the triangulation. When the pointer is not null, the locate will -try to lock all the vertices along the walk. If it succeeds, *could_lock_zone -is true, otherwise it is false. In any case, the locked vertices are not +try to lock all the cells along the walk. If it succeeds, *could_lock_zone +is true, otherwise it is false. In any case, the locked cells are not unlocked by `locate`, leaving this choice to the user. */ Cell_handle @@ -1190,7 +1190,7 @@ incident_cells(Vertex_handle v, OutputIterator cells) const; Try to lock and copy the `Cell_handle`s of all cells incident to `v` into `cells`. Returns true in case of success. Otherwise, `cells` is emptied and the function -returns false. In any case, the locked vertices are not unlocked by +returns false. In any case, the locked cells are not unlocked by `try_lock_and_get_incident_cells`, leaving this choice to the user. \pre `t.dimension() == 3`, `v != Vertex_handle()`, `t.is_vertex(v)`. diff --git a/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt b/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt index cea2f4317fa..717e826e8c0 100644 --- a/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt +++ b/Triangulation_3/doc/Triangulation_3/Triangulation_3.txt @@ -224,6 +224,11 @@ triangulation class, described in Section \ref Triangulation3seclocpol. Optionnally, the main Delaunay and regular triangulations algorithms (insert, remove) support multi-core shared-memory architectures to take advantage of available parallelism. +For this purpose, the user must provide a model of the concept `SpatialLockDataStructure_3`, +such as the `Spatial_grid_lock_data_structure_3` class. This data structure +allows to lock point coordinates (x, y, z) in a 3D domain. When a thread owns the +lock on a point, no other thread can lock this point. Locking a facet (resp. a cell) +boils down to locking all its 3 (resp. 4) incident vertices. \subsection Triangulation3secTraits The Geometric Traits Parameter diff --git a/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h b/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h index d19dd74da4a..180707c5cb4 100644 --- a/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h @@ -489,7 +489,8 @@ public: find_conflicts(const Point &p, Cell_handle c, OutputIteratorBoundaryFacets bfit, OutputIteratorCells cit, - OutputIteratorInternalFacets ifit) const + OutputIteratorInternalFacets ifit, + bool *could_lock_zone = NULL) const { CGAL_triangulation_precondition(dimension() >= 2); @@ -504,7 +505,7 @@ public: (c, tester, make_triple(std::back_inserter(facets), std::back_inserter(cells), - ifit)).third; + ifit, could_lock_zone)).third; } else { Conflict_tester_3 tester(p, this); @@ -512,7 +513,7 @@ public: (c, tester, make_triple(std::back_inserter(facets), std::back_inserter(cells), - ifit)).third; + ifit, could_lock_zone)).third; } // Reset the conflict flag on the boundary. @@ -535,12 +536,14 @@ public: std::pair find_conflicts(const Point &p, Cell_handle c, OutputIteratorBoundaryFacets bfit, - OutputIteratorCells cit) const + OutputIteratorCells cit, + bool *could_lock_zone = NULL) const { Triple t = find_conflicts(p, c, bfit, cit, - Emptyset_iterator()); + Emptyset_iterator(), + could_lock_zone); return std::make_pair(t.first, t.second); } diff --git a/Triangulation_3/include/CGAL/Regular_triangulation_3.h b/Triangulation_3/include/CGAL/Regular_triangulation_3.h index 7a5f8cfa40c..428a918d000 100644 --- a/Triangulation_3/include/CGAL/Regular_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Regular_triangulation_3.h @@ -431,8 +431,8 @@ namespace CGAL { OutputIteratorCells cit, OutputIteratorInternalFacets ifit , bool *could_lock_zone = NULL - , const Facet *p_this_facet_must_be_in_the_cz = 0 - , bool *p_the_facet_is_in_its_cz = 0 + , const Facet *this_facet_must_be_in_the_cz = NULL + , bool *the_facet_is_in_its_cz = NULL ) const { CGAL_triangulation_precondition(dimension() >= 2); @@ -451,8 +451,8 @@ namespace CGAL { std::back_inserter(cells), ifit) , could_lock_zone - , p_this_facet_must_be_in_the_cz - , p_the_facet_is_in_its_cz + , this_facet_must_be_in_the_cz + , the_facet_is_in_its_cz ).third; } else { @@ -464,8 +464,8 @@ namespace CGAL { std::back_inserter(cells), ifit) , could_lock_zone - , p_this_facet_must_be_in_the_cz - , p_the_facet_is_in_its_cz + , this_facet_must_be_in_the_cz + , the_facet_is_in_its_cz ).third; } @@ -496,9 +496,8 @@ namespace CGAL { Triple t = find_conflicts(p, c, bfit, cit, - Emptyset_iterator() - , could_lock_zone - ); + Emptyset_iterator(), + could_lock_zone); return std::make_pair(t.first, t.second); } diff --git a/Triangulation_3/include/CGAL/Triangulation_3.h b/Triangulation_3/include/CGAL/Triangulation_3.h index de6e9c1e434..f238624ff36 100644 --- a/Triangulation_3/include/CGAL/Triangulation_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_3.h @@ -1045,7 +1045,7 @@ public: Cell_handle c, int li, int lj, const Conflict_tester &tester, Hidden_points_visitor &hider, - bool *could_lock_zone = NULL); + bool *could_lock_zone = NULL); template < class InputIterator > std::ptrdiff_t insert(InputIterator first, InputIterator last) @@ -1145,29 +1145,28 @@ protected: // - c is the current cell, which must be in conflict. // - tester is the function object that tests if a cell is in conflict. - template < - class Conflict_test, - class OutputIteratorBoundaryFacets, - class OutputIteratorCells, - class OutputIteratorInternalFacets> + template Triple find_conflicts( Cell_handle d, const Conflict_test &tester, - Triple it + Triple it , bool *could_lock_zone = NULL - , const Facet *p_this_facet_must_be_in_the_cz = 0 - , bool *p_the_facet_is_in_its_cz = 0 + , const Facet *this_facet_must_be_in_the_cz = NULL + , bool *the_facet_is_in_its_cz = NULL ) const { CGAL_triangulation_precondition( dimension()>=2 ); - if (p_the_facet_is_in_its_cz) - *p_the_facet_is_in_its_cz = false; + if (the_facet_is_in_its_cz) + *the_facet_is_in_its_cz = false; if (could_lock_zone) *could_lock_zone = true; @@ -1217,10 +1216,10 @@ protected: Facet f(c, i); // Internal facet. // Is it the facet where're looking for? - if (p_this_facet_must_be_in_the_cz && p_the_facet_is_in_its_cz - && f == *p_this_facet_must_be_in_the_cz) + if (this_facet_must_be_in_the_cz && the_facet_is_in_its_cz + && f == *this_facet_must_be_in_the_cz) { - *p_the_facet_is_in_its_cz = true; + *the_facet_is_in_its_cz = true; } if (c < test) { @@ -1249,10 +1248,10 @@ protected: Facet f(c, i); // Internal facet. // Is it the facet where're looking for? - if (p_this_facet_must_be_in_the_cz && p_the_facet_is_in_its_cz - && f == *p_this_facet_must_be_in_the_cz) + if (this_facet_must_be_in_the_cz && the_facet_is_in_its_cz + && f == *this_facet_must_be_in_the_cz) { - *p_the_facet_is_in_its_cz = true; + *the_facet_is_in_its_cz = true; } if (c < test) @@ -1271,13 +1270,13 @@ protected: Facet f(c, i); // Boundary facet. // Is it the facet where're looking for? - if (p_this_facet_must_be_in_the_cz - && p_the_facet_is_in_its_cz + if (this_facet_must_be_in_the_cz + && the_facet_is_in_its_cz && - (mirror_facet(f) == *p_this_facet_must_be_in_the_cz - || f == *p_this_facet_must_be_in_the_cz) ) + (mirror_facet(f) == *this_facet_must_be_in_the_cz + || f == *this_facet_must_be_in_the_cz) ) { - *p_the_facet_is_in_its_cz = true; + *the_facet_is_in_its_cz = true; } *it.first++ = f;