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