Wait for threads in iterator destructor

This commit is contained in:
Thomas Krijnen
2024-03-15 13:57:44 +01:00
parent 16fa8573d3
commit 8aa3b12911
+101 -86
View File
@@ -1,58 +1,58 @@
/******************************************************************************** /********************************************************************************
* * * *
* This file is part of IfcOpenShell. * * This file is part of IfcOpenShell. *
* * * *
* IfcOpenShell is free software: you can redistribute it and/or modify * * IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by * * it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or * * the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
* IfcOpenShell is distributed in the hope that it will be useful, * * IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. * * Lesser GNU General Public License for more details. *
* * * *
* You should have received a copy of the Lesser GNU General Public License * * You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
* * * *
********************************************************************************/ ********************************************************************************/
/******************************************************************************** /********************************************************************************
* * * *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) * * Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). * * and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* * * *
* IfcGeom::Representation::Triangulation is a class that represents a * * IfcGeom::Representation::Triangulation is a class that represents a *
* triangulated IfcShapeRepresentation. * * triangulated IfcShapeRepresentation. *
* Triangulation.verts is a 1 dimensional vector of float defining the * * Triangulation.verts is a 1 dimensional vector of float defining the *
* cartesian coordinates of the vertices of the triangulated shape in the * * cartesian coordinates of the vertices of the triangulated shape in the *
* format of [x1,y1,z1,..,xn,yn,zn] * * format of [x1,y1,z1,..,xn,yn,zn] *
* Triangulation.faces is a 1 dimensional vector of int containing the * * Triangulation.faces is a 1 dimensional vector of int containing the *
* indices of the triangles referencing positions in Triangulation.verts * * indices of the triangles referencing positions in Triangulation.verts *
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates* * Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
* the visibility of the edges that span the faces in Triangulation.faces * * the visibility of the edges that span the faces in Triangulation.faces *
* * * *
* IfcGeom::Element represents the actual IfcBuildingElements. * * IfcGeom::Element represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element * * IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow * * IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh * * IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the * * IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
* orientation and translation of the mesh in relation to the world origin * * orientation and translation of the mesh in relation to the world origin *
* * * *
* IfcGeom::Iterator::initialize() * * IfcGeom::Iterator::initialize() *
* finds the most suitable representation contexts. Returns true iff * * finds the most suitable representation contexts. Returns true iff *
* at least a single representation will process successfully * * at least a single representation will process successfully *
* * * *
* IfcGeom::Iterator::get() * * IfcGeom::Iterator::get() *
* returns a pointer to the current IfcGeom::Element * * returns a pointer to the current IfcGeom::Element *
* * * *
* IfcGeom::Iterator::next() * * IfcGeom::Iterator::next() *
* returns true iff a following entity is available for a successive call to * * returns true iff a following entity is available for a successive call to *
* IfcGeom::Iterator::get() * * IfcGeom::Iterator::get() *
* * * *
* IfcGeom::Iterator::progress() * * IfcGeom::Iterator::progress() *
* returns an int in [0..100] that indicates the overall progress * * returns an int in [0..100] that indicates the overall progress *
* * * *
********************************************************************************/ ********************************************************************************/
#ifndef IFCGEOMITERATOR_H #ifndef IFCGEOMITERATOR_H
@@ -102,6 +102,7 @@ namespace IfcGeom {
GeometrySerializer* cache_ = nullptr; GeometrySerializer* cache_ = nullptr;
std::atomic<bool> finished_{ false }; std::atomic<bool> finished_{ false };
std::atomic<bool> terminating_{ false };
std::atomic<int> progress_{ 0 }; std::atomic<int> progress_{ 0 };
std::vector<geometry_conversion_result> tasks_; std::vector<geometry_conversion_result> tasks_;
@@ -148,13 +149,13 @@ namespace IfcGeom {
std::string unit_name_; std::string unit_name_;
double unit_magnitude_; double unit_magnitude_;
ifcopenshell::geometry::taxonomy::point3 bounds_min_; ifcopenshell::geometry::taxonomy::point3 bounds_min_;
ifcopenshell::geometry::taxonomy::point3 bounds_max_; ifcopenshell::geometry::taxonomy::point3 bounds_max_;
// Should not be destructed because, destructor is blocking // Should not be destructed because, destructor is blocking
std::future<void> init_future_; std::future<void> init_future_;
/// @todo public/private sections all over the place: move all public to the beginning of the class /// @todo public/private sections all over the place: move all public to the beginning of the class
public: public:
void set_cache(GeometrySerializer* cache) { cache_ = cache; } void set_cache(GeometrySerializer* cache) { cache_ = cache; }
@@ -302,7 +303,7 @@ namespace IfcGeom {
break; break;
} // if } // if
} // for } // for
} // while } // while
std::future<geometry_conversion_result*> fu = std::async( std::future<geometry_conversion_result*> fu = std::async(
std::launch::async, [this]( std::launch::async, [this](
@@ -316,6 +317,10 @@ namespace IfcGeom {
std::ref(settings_), std::ref(settings_),
&rep); &rep);
if (terminating_) {
break;
}
threadpool.emplace_back(std::move(fu)); threadpool.emplace_back(std::move(fu));
} }
@@ -327,18 +332,20 @@ namespace IfcGeom {
Logger::SetProduct(boost::none); Logger::SetProduct(boost::none);
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) + if (!terminating_) {
" objects) "); Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) +
" objects) ");
}
} }
/// Computes model's bounding box (bounds_min and bounds_max). /// Computes model's bounding box (bounds_min and bounds_max).
/// @note Can take several minutes for large files. /// @note Can take several minutes for large files.
void compute_bounds(bool with_geometry) void compute_bounds(bool with_geometry)
{ {
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
bounds_min_.components()(i) = std::numeric_limits<double>::infinity(); bounds_min_.components()(i) = std::numeric_limits<double>::infinity();
bounds_max_.components()(i) = -std::numeric_limits<double>::infinity(); bounds_max_.components()(i) = -std::numeric_limits<double>::infinity();
} }
if (with_geometry) { if (with_geometry) {
size_t num_created = 0; size_t num_created = 0;
@@ -381,7 +388,7 @@ namespace IfcGeom {
} }
} }
} }
} }
int progress() const { int progress() const {
return progress_; return progress_;
@@ -391,11 +398,11 @@ namespace IfcGeom {
IfcParse::IfcFile* file() const { return ifc_file; } IfcParse::IfcFile* file() const { return ifc_file; }
const std::vector<IfcGeom::filter_t>& filters() const { return filters_; } const std::vector<IfcGeom::filter_t>& filters() const { return filters_; }
std::vector<IfcGeom::filter_t>& filters() { return filters_; } std::vector<IfcGeom::filter_t>& filters() { return filters_; }
const ifcopenshell::geometry::taxonomy::point3& bounds_min() const { return bounds_min_; } const ifcopenshell::geometry::taxonomy::point3& bounds_min() const { return bounds_min_; }
const ifcopenshell::geometry::taxonomy::point3& bounds_max() const { return bounds_max_; } const ifcopenshell::geometry::taxonomy::point3& bounds_max() const { return bounds_max_; }
private: private:
@@ -558,23 +565,23 @@ namespace IfcGeom {
} }
} }
public: public:
/// Returns what would be the product for the next shape representation /// Returns what would be the product for the next shape representation
/// @todo Double-check and test the impl. /// @todo Double-check and test the impl.
//IfcSchema::IfcProduct* peek_next() const //IfcSchema::IfcProduct* peek_next() const
//{ //{
// if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){ // if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){
// return *(ifcproduct_iterator + 1); // return *(ifcproduct_iterator + 1);
// } else { // } else {
// return 0; // return 0;
// } // }
//} //}
/// @todo Would this be as simple as the following code? /// @todo Would this be as simple as the following code?
//void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } } //void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } }
/// Moves to the next shape representation, create its geometry, and returns the associated product. /// Moves to the next shape representation, create its geometry, and returns the associated product.
/// Use get() to retrieve the created geometry. /// Use get() to retrieve the created geometry.
const IfcUtil::IfcBaseClass* next() { const IfcUtil::IfcBaseClass* next() {
if (num_threads_ != 1) { if (num_threads_ != 1) {
if (!wait_for_element()) { if (!wait_for_element()) {
@@ -602,10 +609,10 @@ namespace IfcGeom {
} }
} }
/// Gets the representation of the current geometrical entity. /// Gets the representation of the current geometrical entity.
Element* get() Element* get()
{ {
auto ret = *task_result_iterator_; auto ret = *task_result_iterator_;
// If we want to organize the element considering their hierarchy // If we want to organize the element considering their hierarchy
if (settings_.get<ifcopenshell::geometry::settings::UseElementHierarchy>().get()) if (settings_.get<ifcopenshell::geometry::settings::UseElementHierarchy>().get())
@@ -653,8 +660,8 @@ namespace IfcGeom {
} }
} }
return ret; return ret;
} }
/// Gets the native (Open Cascade or CGAL) representation of the current geometrical entity. /// Gets the native (Open Cascade or CGAL) representation of the current geometrical entity.
BRepElement* get_native() BRepElement* get_native()
@@ -666,7 +673,7 @@ namespace IfcGeom {
ifcopenshell::geometry::taxonomy::matrix4::ptr m4; ifcopenshell::geometry::taxonomy::matrix4::ptr m4;
int parent_id = -1; int parent_id = -1;
std::string instance_type, product_name, product_guid; std::string instance_type, product_name, product_guid;
IfcUtil::IfcBaseEntity* ifc_product = 0; IfcUtil::IfcBaseEntity* ifc_product = 0;
try { try {
IfcUtil::IfcBaseEntity* ifc_entity = ifc_file->instance_by_id(id)->as<IfcUtil::IfcBaseEntity>(); IfcUtil::IfcBaseEntity* ifc_entity = ifc_file->instance_by_id(id)->as<IfcUtil::IfcBaseEntity>();
@@ -773,6 +780,14 @@ namespace IfcGeom {
} }
~Iterator() { ~Iterator() {
if (num_threads_ != 1) {
terminating_ = true;
if (init_future_.valid()) {
init_future_.wait();
}
}
if (owns_ifc_file) { if (owns_ifc_file) {
delete ifc_file; delete ifc_file;
} }
@@ -787,7 +802,7 @@ namespace IfcGeom {
delete k; delete k;
} }
for (auto& p : all_processed_elements_) { for (auto& p : all_processed_elements_) {
delete p; delete p;
} }
} }