#3013 Make sure all existing connections for PdmObjects are removed before async delete

* Clear all PdmPointer connections (including selection manager)
* Send all threads to the new caf::AsyncWorkerManager which can join the threads
  before program exit if the caller has asked for that.
This commit is contained in:
Gaute Lindkvist 2018-06-08 12:57:58 +02:00
parent d52c7b4119
commit 5f766e5228
9 changed files with 210 additions and 70 deletions

View File

@ -72,7 +72,8 @@ void RicCloseSummaryCaseFeature::deleteSummaryCases(std::vector<RimSummaryCase*>
RiuPlotMainWindow* mainPlotWindow = RiaApplication::instance()->mainPlotWindow();
mainPlotWindow->updateSummaryPlotToolBar();
caf::AsyncRawPointerVectorDeleter<RimSummaryCase> summaryCaseDeleter(std::move(cases));
caf::AsyncPdmObjectVectorDeleter<RimSummaryCase> summaryCaseDeleter(cases);
CAF_ASSERT(cases.empty()); // vector should be empty immediately.
}
//--------------------------------------------------------------------------------------------------

View File

@ -47,7 +47,8 @@ set( PROJECT_FILES
cafFilePath.h
cafAsyncObjectDeleter.h
cafAsyncObjectDeleter.inl
cafAsyncWorkerManager.h
cafAsyncWorkerManager.cpp
)
add_library( ${PROJECT_NAME}

View File

@ -38,26 +38,16 @@
namespace caf
{
template<typename T>
class AsyncRawPointerVectorDeleter
template<typename PdmObjectType>
class AsyncPdmObjectVectorDeleter
{
public:
AsyncRawPointerVectorDeleter(std::vector<T*>&& pointerVector);
~AsyncRawPointerVectorDeleter();
AsyncPdmObjectVectorDeleter(std::vector<PdmObjectType*>& pointerVector);
AsyncPdmObjectVectorDeleter(std::vector<PdmPointer<PdmObjectType>>& pdmPointerVector);
~AsyncPdmObjectVectorDeleter();
void start();
private:
std::vector<T*> m_pointersToDelete;
};
template<typename T>
class AsyncPdmPointerVectorDeleter
{
public:
AsyncPdmPointerVectorDeleter(std::vector<PdmPointer<T>>&& pdmPointerVector);
~AsyncPdmPointerVectorDeleter();
void start();
private:
std::vector<PdmPointer<T>> m_pointersToDelete;
std::vector<PdmObjectHandle*> m_pointersToDelete;
};
}

View File

@ -1,58 +1,52 @@
#include <thread>
#include "cafAsyncWorkerManager.h"
namespace caf
{
//--------------------------------------------------------------------------------------------------
/// Constructor that takes ownership of the data in the provided vector
//--------------------------------------------------------------------------------------------------
template<typename T>
AsyncRawPointerVectorDeleter<T>::AsyncRawPointerVectorDeleter(std::vector<T*>&& pointerVector)
: m_pointersToDelete(std::move(pointerVector))
template<typename PdmObjectType>
AsyncPdmObjectVectorDeleter<PdmObjectType>::AsyncPdmObjectVectorDeleter(std::vector<PdmObjectType*>& pointerVector)
{
}
//--------------------------------------------------------------------------------------------------
/// Destructor will launch the asynchronous deletion if start() hasn't already been run.
//--------------------------------------------------------------------------------------------------
template<typename T>
AsyncRawPointerVectorDeleter<T>::~AsyncRawPointerVectorDeleter()
{
if (!m_pointersToDelete.empty())
m_pointersToDelete.reserve(pointerVector.size());
for (PdmObjectType* rawPointer : pointerVector)
{
start();
}
}
//--------------------------------------------------------------------------------------------------
/// Perform deletion of the pointers in a separate thread.
//--------------------------------------------------------------------------------------------------
template<typename T>
void AsyncRawPointerVectorDeleter<T>::start()
{
std::thread([](std::vector<T*>&& pointerVector)
{
for (T* pointerToDelete : pointerVector)
if (rawPointer)
{
delete pointerToDelete;
PdmObjectHandle* objectHandle = static_cast<PdmObjectHandle*>(rawPointer);
objectHandle->prepareForDelete();
m_pointersToDelete.push_back(objectHandle);
}
}, std::move(m_pointersToDelete)).detach();
}
pointerVector.clear();
}
//--------------------------------------------------------------------------------------------------
/// Constructor that takes ownership of the data in the provided vector
//--------------------------------------------------------------------------------------------------
template<typename T>
AsyncPdmPointerVectorDeleter<T>::AsyncPdmPointerVectorDeleter(std::vector<PdmPointer<T>>&& pdmPointerVector)
: m_pointersToDelete(std::move(pdmPointerVector))
template<typename PdmObjectType>
AsyncPdmObjectVectorDeleter<PdmObjectType>::AsyncPdmObjectVectorDeleter(std::vector<PdmPointer<PdmObjectType>>& pdmPointerVector)
{
m_pointersToDelete.reserve(pdmPointerVector.size());
for (PdmPointer<PdmObjectType>& pdmPointer : pdmPointerVector)
{
if (pdmPointer.notNull())
{
PdmObjectHandle* objectHandle = pdmPointer.rawPtr();
objectHandle->prepareForDelete();
m_pointersToDelete.push_back(objectHandle);
}
}
pdmPointerVector.clear();
}
//--------------------------------------------------------------------------------------------------
/// Destructor will launch the asynchronous deletion if start() hasn't already been run.
//--------------------------------------------------------------------------------------------------
template<typename T>
AsyncPdmPointerVectorDeleter<T>::~AsyncPdmPointerVectorDeleter()
template<typename PdmObjectType>
AsyncPdmObjectVectorDeleter<PdmObjectType>::~AsyncPdmObjectVectorDeleter()
{
if (!m_pointersToDelete.empty())
{
@ -63,16 +57,17 @@ namespace caf
//--------------------------------------------------------------------------------------------------
/// Perform deletion of the pointers in a separate thread.
//--------------------------------------------------------------------------------------------------
template<typename T>
void AsyncPdmPointerVectorDeleter<T>::start()
template<typename PdmObjectType>
void AsyncPdmObjectVectorDeleter<PdmObjectType>::start()
{
std::thread([](std::vector<PdmPointer<T>>&& pointerVector)
std::thread thread([](std::vector<PdmObjectHandle*>&& pointerVector)
{
for (PdmPointer<T>& pointerToDelete : pointerVector)
for (PdmObjectHandle* pointerToDelete : pointerVector)
{
delete pointerToDelete.rawPtr();
delete pointerToDelete;
}
}, std::move(m_pointersToDelete)).detach();
}, std::move(m_pointersToDelete));
AsyncWorkerManager::instance().takeThreadOwnership(thread, false);
}
}

View File

@ -0,0 +1,81 @@
//##################################################################################################
//
// 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 <<http://www.gnu.org/licenses/gpl.html>>
// 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 <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include "cafAsyncWorkerManager.h"
//--------------------------------------------------------------------------------------------------
/// Create a static thread manager that is cleared when the program ends.
//--------------------------------------------------------------------------------------------------
caf::AsyncWorkerManager& caf::AsyncWorkerManager::instance()
{
static AsyncWorkerManager manager;
return manager;
}
//--------------------------------------------------------------------------------------------------
/// Destructor waiting for threads to join.
//--------------------------------------------------------------------------------------------------
caf::AsyncWorkerManager::~AsyncWorkerManager()
{
for (ThreadAndJoinAtExitPair& workerThreadAndJoinFlag : m_threads)
{
if (workerThreadAndJoinFlag.second && workerThreadAndJoinFlag.first.joinable())
{
workerThreadAndJoinFlag.first.join();
}
else
{
workerThreadAndJoinFlag.first.detach();
}
}
}
//--------------------------------------------------------------------------------------------------
/// Takes over ownership of the thread and the caller no longer has access to it.
/// A flag can be provided to force the Worker manager to join the threads on exit.
/// Set this to true if it is important that the thread finishes before the program exits.
//--------------------------------------------------------------------------------------------------
void caf::AsyncWorkerManager::takeThreadOwnership(std::thread& thread, bool joinAtExit)
{
m_threads.push_back(std::make_pair(std::move(thread), joinAtExit));
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::AsyncWorkerManager::AsyncWorkerManager()
{
}

View File

@ -0,0 +1,56 @@
//##################################################################################################
//
// 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 <<http://www.gnu.org/licenses/gpl.html>>
// 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 <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#pragma once
#include <memory>
#include <thread>
#include <vector>
namespace caf
{
class AsyncWorkerManager
{
public:
static AsyncWorkerManager& AsyncWorkerManager::instance();
~AsyncWorkerManager();
void takeThreadOwnership(std::thread& thread, bool joinAtExit);
private:
typedef std::pair<std::thread, bool> ThreadAndJoinAtExitPair;
AsyncWorkerManager();
std::vector<ThreadAndJoinAtExitPair> m_threads;
};
}

View File

@ -148,7 +148,7 @@ void PdmChildArrayField<DataType*>::deleteAllChildObjectsAsync()
{
CAF_ASSERT(isInitializedByInitFieldMacro());
AsyncPdmPointerVectorDeleter<DataType> pointerDeleter(std::move(m_pointers));
AsyncPdmObjectVectorDeleter<DataType> pointerDeleter(m_pointers);
CAF_ASSERT(m_pointers.empty()); // Object storage for m_pointers should be empty immediately.
}

View File

@ -14,18 +14,7 @@ namespace caf
//--------------------------------------------------------------------------------------------------
PdmObjectHandle::~PdmObjectHandle()
{
for (size_t i = 0; i < m_capabilities.size(); ++i)
{
if (m_capabilities[i].second) delete m_capabilities[i].first;
}
// Set all guarded pointers pointing to this to NULL
std::set<PdmObjectHandle**>::iterator it;
for (it = m_pointersReferencingMe.begin(); it != m_pointersReferencingMe.end() ; ++it)
{
(**it) = nullptr;
}
this->prepareForDelete();
}
//--------------------------------------------------------------------------------------------------
@ -102,6 +91,30 @@ void PdmObjectHandle::objectsWithReferringPtrFields(std::vector<PdmObjectHandle*
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmObjectHandle::prepareForDelete()
{
m_parentField = nullptr;
for (size_t i = 0; i < m_capabilities.size(); ++i)
{
if (m_capabilities[i].second) delete m_capabilities[i].first;
}
// Set all guarded pointers pointing to this to NULL
std::set<PdmObjectHandle**>::iterator it;
for (it = m_pointersReferencingMe.begin(); it != m_pointersReferencingMe.end(); ++it)
{
(**it) = nullptr;
}
m_capabilities.clear();
m_referencingPtrFields.clear();
m_pointersReferencingMe.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -54,6 +54,9 @@ public:
/// Convenience method to get the objects pointing to this field
void objectsWithReferringPtrFields(std::vector<PdmObjectHandle*>& objects) const;
// Detach object from all referring fields
void prepareForDelete();
// Object capabilities
void addCapability(PdmObjectCapability* capability, bool takeOwnership) { m_capabilities.push_back(std::make_pair(capability, takeOwnership)); }