From 743993718c7174d4b29d244174249ecd3b819e5e Mon Sep 17 00:00:00 2001 From: Gaute Lindkvist Date: Tue, 22 May 2018 09:36:31 +0200 Subject: [PATCH] #2873 New AsyncPointerVectorDeleter-classes to handle memory deletion in separate thread. --- .../Commands/RicCloseSummaryCaseFeature.cpp | 7 +- .../Commands/RicCloseSummaryCaseFeature.h | 2 +- ...RicCloseSummaryCaseInCollectionFeature.cpp | 6 +- .../Summary/RimSummaryCaseCollection.cpp | 2 +- .../Summary/RimSummaryCaseMainCollection.cpp | 4 +- .../cafPdmCore/CMakeLists.txt | 3 + .../cafPdmCore/cafAsyncObjectDeleter.h | 64 +++++++++++++++ .../cafPdmCore/cafAsyncObjectDeleter.inl | 78 +++++++++++++++++++ .../cafPdmCore/cafPdmChildArrayField.h | 3 +- .../cafPdmCore/cafPdmChildArrayField.inl | 15 ++++ 10 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAsyncObjectDeleter.h create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAsyncObjectDeleter.inl diff --git a/ApplicationCode/Commands/RicCloseSummaryCaseFeature.cpp b/ApplicationCode/Commands/RicCloseSummaryCaseFeature.cpp index 8471ef0cd7..b2d08b010e 100644 --- a/ApplicationCode/Commands/RicCloseSummaryCaseFeature.cpp +++ b/ApplicationCode/Commands/RicCloseSummaryCaseFeature.cpp @@ -30,6 +30,7 @@ #include "RiuPlotMainWindow.h" +#include "cafAsyncObjectDeleter.h" #include "cafSelectionManager.h" #include "cvfAssert.h" @@ -50,7 +51,7 @@ void RicCloseSummaryCaseFeature::setupActionLook(QAction* actionToSetup) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicCloseSummaryCaseFeature::deleteSummaryCases(const std::vector& cases) +void RicCloseSummaryCaseFeature::deleteSummaryCases(std::vector& cases) { RimSummaryPlotCollection* summaryPlotColl = RiaSummaryTools::summaryPlotCollection(); @@ -66,13 +67,13 @@ void RicCloseSummaryCaseFeature::deleteSummaryCases(const std::vectorfirstAncestorOrThisOfTypeAsserted(summaryCaseMainCollection); summaryCaseMainCollection->removeCase(summaryCase); - delete summaryCase; - summaryCaseMainCollection->updateAllRequiredEditors(); } RiuPlotMainWindow* mainPlotWindow = RiaApplication::instance()->mainPlotWindow(); mainPlotWindow->updateSummaryPlotToolBar(); + + caf::AsyncRawPointerVectorDeleter summaryCaseDeleter(std::move(cases)); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/RicCloseSummaryCaseFeature.h b/ApplicationCode/Commands/RicCloseSummaryCaseFeature.h index d987aba447..c0a45ce5f5 100644 --- a/ApplicationCode/Commands/RicCloseSummaryCaseFeature.h +++ b/ApplicationCode/Commands/RicCloseSummaryCaseFeature.h @@ -32,7 +32,7 @@ class RicCloseSummaryCaseFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; public: - static void deleteSummaryCases(const std::vector& cases); + static void deleteSummaryCases(std::vector& cases); protected: // Overrides diff --git a/ApplicationCode/Commands/RicCloseSummaryCaseInCollectionFeature.cpp b/ApplicationCode/Commands/RicCloseSummaryCaseInCollectionFeature.cpp index efe1de1016..9fad686df0 100644 --- a/ApplicationCode/Commands/RicCloseSummaryCaseInCollectionFeature.cpp +++ b/ApplicationCode/Commands/RicCloseSummaryCaseInCollectionFeature.cpp @@ -75,7 +75,8 @@ void RicCloseSummaryCaseInCollectionFeature::onActionTriggered(bool isChecked) if (summaryCaseMainCollections.size() > 0) { - RicCloseSummaryCaseFeature::deleteSummaryCases(summaryCaseMainCollections[0]->allSummaryCases()); + std::vector allSummaryCases = summaryCaseMainCollections[0]->allSummaryCases(); + RicCloseSummaryCaseFeature::deleteSummaryCases(allSummaryCases); } std::vector summaryCaseCollections; @@ -83,7 +84,8 @@ void RicCloseSummaryCaseInCollectionFeature::onActionTriggered(bool isChecked) for (RimSummaryCaseCollection* summaryCaseCollection : summaryCaseCollections) { - RicCloseSummaryCaseFeature::deleteSummaryCases(summaryCaseCollection->allSummaryCases()); + std::vector collectionSummaryCases = summaryCaseCollection->allSummaryCases(); + RicCloseSummaryCaseFeature::deleteSummaryCases(collectionSummaryCases); } RiuPlotMainWindow* mainPlotWindow = RiaApplication::instance()->mainPlotWindow(); diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp index 6d962faaff..5c70c6ca96 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp @@ -53,7 +53,7 @@ RimSummaryCaseCollection::RimSummaryCaseCollection() //-------------------------------------------------------------------------------------------------- RimSummaryCaseCollection::~RimSummaryCaseCollection() { - m_cases.deleteAllChildObjects(); + m_cases.deleteAllChildObjectsAsync(); updateReferringCurveSets(); } diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp index 45b2a78c0c..e1db6de4c7 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseMainCollection.cpp @@ -75,8 +75,8 @@ RimSummaryCaseMainCollection::RimSummaryCaseMainCollection() //-------------------------------------------------------------------------------------------------- RimSummaryCaseMainCollection::~RimSummaryCaseMainCollection() { - m_cases.deleteAllChildObjects(); - m_caseCollections.deleteAllChildObjects(); + m_cases.deleteAllChildObjectsAsync(); + m_caseCollections.deleteAllChildObjectsAsync(); } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt index 40e8db36b0..12068aa1f4 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt @@ -45,6 +45,9 @@ set( PROJECT_FILES cafTristate.h cafFilePath.cpp cafFilePath.h + cafAsyncObjectDeleter.h + cafAsyncObjectDeleter.inl + ) add_library( ${PROJECT_NAME} diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAsyncObjectDeleter.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAsyncObjectDeleter.h new file mode 100644 index 0000000000..1c1aab7f1a --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAsyncObjectDeleter.h @@ -0,0 +1,64 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2011-2013 Ceetron AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This library 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 GNU General Public License at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 GNU Lesser General Public License at <> +// for more details. +// +//################################################################################################## + +#pragma once + +namespace caf +{ + template + class AsyncRawPointerVectorDeleter + { + public: + AsyncRawPointerVectorDeleter(std::vector&& pointerVector); + ~AsyncRawPointerVectorDeleter(); + void start(); + private: + std::vector m_pointersToDelete; + }; + + template + class AsyncPdmPointerVectorDeleter + { + public: + AsyncPdmPointerVectorDeleter(std::vector>&& pdmPointerVector); + ~AsyncPdmPointerVectorDeleter(); + void start(); + private: + std::vector> m_pointersToDelete; + }; +} + +#include "cafAsyncObjectDeleter.inl" diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAsyncObjectDeleter.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAsyncObjectDeleter.inl new file mode 100644 index 0000000000..15117a068c --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAsyncObjectDeleter.inl @@ -0,0 +1,78 @@ +#include + +namespace caf +{ + //-------------------------------------------------------------------------------------------------- + /// Constructor that takes ownership of the data in the provided vector + //-------------------------------------------------------------------------------------------------- + template + AsyncRawPointerVectorDeleter::AsyncRawPointerVectorDeleter(std::vector&& pointerVector) + : m_pointersToDelete(std::move(pointerVector)) + { + } + + //-------------------------------------------------------------------------------------------------- + /// Destructor will launch the asynchronous deletion if start() hasn't already been run. + //-------------------------------------------------------------------------------------------------- + template + AsyncRawPointerVectorDeleter::~AsyncRawPointerVectorDeleter() + { + if (!m_pointersToDelete.empty()) + { + start(); + } + } + + //-------------------------------------------------------------------------------------------------- + /// Perform deletion of the pointers in a separate thread. + //-------------------------------------------------------------------------------------------------- + template + void AsyncRawPointerVectorDeleter::start() + { + std::thread([](std::vector&& pointerVector) + { + for (T* pointerToDelete : pointerVector) + { + delete pointerToDelete; + } + }, std::move(m_pointersToDelete)).detach(); + } + + + //-------------------------------------------------------------------------------------------------- + /// Constructor that takes ownership of the data in the provided vector + //-------------------------------------------------------------------------------------------------- + template + AsyncPdmPointerVectorDeleter::AsyncPdmPointerVectorDeleter(std::vector>&& pdmPointerVector) + : m_pointersToDelete(std::move(pdmPointerVector)) + { + } + + //-------------------------------------------------------------------------------------------------- + /// Destructor will launch the asynchronous deletion if start() hasn't already been run. + //-------------------------------------------------------------------------------------------------- + template + AsyncPdmPointerVectorDeleter::~AsyncPdmPointerVectorDeleter() + { + if (!m_pointersToDelete.empty()) + { + start(); + } + } + + //-------------------------------------------------------------------------------------------------- + /// Perform deletion of the pointers in a separate thread. + //-------------------------------------------------------------------------------------------------- + template + void AsyncPdmPointerVectorDeleter::start() + { + std::thread([](std::vector>&& pointerVector) + { + for (PdmPointer& pointerToDelete : pointerVector) + { + delete pointerToDelete.rawPtr(); + } + }, std::move(m_pointersToDelete)).detach(); + } + +} \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.h index c3546cecd8..311b8dc182 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.h @@ -61,7 +61,8 @@ public: virtual size_t size() const { return m_pointers.size(); } virtual bool empty() const { return m_pointers.empty(); } virtual void clear(); - virtual void deleteAllChildObjects(); + virtual void deleteAllChildObjects(); + virtual void deleteAllChildObjectsAsync(); virtual void insertAt(int indexAfter, PdmObjectHandle* obj); virtual PdmObjectHandle* at(size_t index); diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.inl index 019111b2e5..1b5c73eba0 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.inl +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.inl @@ -1,3 +1,4 @@ +#include "cafAsyncObjectDeleter.h" #include "cafClassTypeName.h" #include "cafPdmObjectHandle.h" @@ -138,6 +139,20 @@ void PdmChildArrayField::deleteAllChildObjects() m_pointers.clear(); } +//-------------------------------------------------------------------------------------------------- +/// Transfers ownership of the objects pointed to a separate thread. +/// Then clears the container and lets the thread delete the objects. +//-------------------------------------------------------------------------------------------------- +template +void PdmChildArrayField::deleteAllChildObjectsAsync() +{ + CAF_ASSERT(isInitializedByInitFieldMacro()); + + AsyncPdmPointerVectorDeleter pointerDeleter(std::move(m_pointers)); + CAF_ASSERT(m_pointers.empty()); // Object storage for m_pointers should be empty immediately. +} + + //-------------------------------------------------------------------------------------------------- /// Removes the pointer at index from the container. Does not delete the object pointed to. /// Todo: This implementation can't be necessary in the new regime. Should be to just remove