Fixed director destruction (#20)
* Added/modified Accessor destructors to clear all scheduled callbacks and destroy children in order first to avoid dangling references. Added Port destructors to disconnect on destruction. * Fixed director destruction bug
This commit is contained in:
Родитель
e257cd15b7
Коммит
62db905764
|
@ -65,8 +65,6 @@ private:
|
|||
using CompositeAccessor::AddInputPorts;
|
||||
using CompositeAccessor::AddOutputPort;
|
||||
using CompositeAccessor::AddOutputPorts;
|
||||
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
class HostHypervisor
|
||||
|
|
|
@ -49,7 +49,7 @@ void Accessor::Impl::ResetPriority()
|
|||
this->m_priority = DefaultAccessorPriority;
|
||||
}
|
||||
|
||||
std::shared_ptr<Director> Accessor::Impl::GetDirector() const
|
||||
Director* Accessor::Impl::GetDirector() const
|
||||
{
|
||||
auto myParent = static_cast<CompositeAccessor::Impl*>(this->GetParent());
|
||||
if (myParent == nullptr)
|
||||
|
@ -116,8 +116,7 @@ int Accessor::Impl::ScheduleCallback(
|
|||
int delayInMilliseconds,
|
||||
bool repeat)
|
||||
{
|
||||
auto director = this->GetDirector();
|
||||
int callbackId = director->ScheduleCallback(
|
||||
int callbackId = this->GetDirector()->ScheduleCallback(
|
||||
callback,
|
||||
delayInMilliseconds,
|
||||
repeat,
|
||||
|
@ -128,12 +127,7 @@ int Accessor::Impl::ScheduleCallback(
|
|||
|
||||
void Accessor::Impl::ClearScheduledCallback(int callbackId)
|
||||
{
|
||||
auto director = this->GetDirector();
|
||||
if (director.get() != nullptr)
|
||||
{
|
||||
director->ClearScheduledCallback(callbackId);
|
||||
}
|
||||
|
||||
this->GetDirector()->ClearScheduledCallback(callbackId);
|
||||
this->m_callbackIds.erase(callbackId);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
int GetPriority() const;
|
||||
void SetPriority(int priority);
|
||||
virtual void ResetPriority();
|
||||
virtual std::shared_ptr<Director> GetDirector() const;
|
||||
virtual Director* GetDirector() const;
|
||||
bool HasInputPorts() const;
|
||||
bool HasOutputPorts() const;
|
||||
InputPort* GetInputPort(const std::string& portName) const;
|
||||
|
|
|
@ -18,7 +18,6 @@ CompositeAccessor::Impl::Impl(
|
|||
|
||||
CompositeAccessor::Impl::~Impl()
|
||||
{
|
||||
// base class dtor will clear all scheduled callbacks first
|
||||
this->RemoveAllChildren();
|
||||
}
|
||||
|
||||
|
@ -54,9 +53,7 @@ void CompositeAccessor::Impl::ScheduleReaction(Accessor::Impl* child, int priori
|
|||
{
|
||||
this->m_reactionRequested = true;
|
||||
this->m_childEventQueue.push(child);
|
||||
|
||||
auto director = this->GetDirector();
|
||||
director->ScheduleCallback(
|
||||
this->GetDirector()->ScheduleCallback(
|
||||
[this]() { this->ProcessChildEventQueue(); },
|
||||
0 /*delayInMilliseconds*/,
|
||||
false /*repeat*/,
|
||||
|
|
|
@ -17,7 +17,7 @@ Director::Director() :
|
|||
m_startTime(this->m_currentLogicalTime),
|
||||
m_nextScheduledExecutionTime(DefaultNextExecutionTime),
|
||||
m_executionResult(nullptr),
|
||||
m_currentExecutionCancellationToken(nullptr)
|
||||
m_executionCancellationToken(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ int Director::ScheduleCallback(
|
|||
this->QueueScheduledCallback(newCallbackId);
|
||||
if (this->m_nextScheduledExecutionTime > newCallback.nextExecutionTimeInMilliseconds)
|
||||
{
|
||||
this->CancelNextExecution();
|
||||
this->StopExecution();
|
||||
this->m_nextScheduledExecutionTime = newCallback.nextExecutionTimeInMilliseconds;
|
||||
this->ScheduleNextExecution();
|
||||
}
|
||||
|
@ -85,16 +85,19 @@ void Director::HandlePriorityUpdate(int oldPriority, int newPriority)
|
|||
}
|
||||
}
|
||||
|
||||
void Director::Execute(std::shared_ptr<CancellationToken> executionCancellationToken, int numberOfIterations)
|
||||
void Director::Execute(int numberOfIterations)
|
||||
{
|
||||
if (this->m_currentExecutionCancellationToken.get() == nullptr || this->m_currentExecutionCancellationToken->IsCanceled())
|
||||
if (this->m_executionCancellationToken.get() == nullptr || this->m_executionCancellationToken->IsCanceled())
|
||||
{
|
||||
this->ScheduleNextExecution();
|
||||
}
|
||||
|
||||
auto executionResult = this->m_executionResult;
|
||||
int currentIteration = 0;
|
||||
while (!executionCancellationToken->IsCanceled() && executionResult->valid() && (numberOfIterations == 0 || currentIteration < numberOfIterations))
|
||||
while (this->m_executionCancellationToken != nullptr &&
|
||||
!this->m_executionCancellationToken->IsCanceled() &&
|
||||
executionResult->valid() &&
|
||||
(numberOfIterations == 0 || currentIteration < numberOfIterations))
|
||||
{
|
||||
PRINT_DEBUG("-----NEXT ROUND-----");
|
||||
bool wasCanceled = executionResult->get();
|
||||
|
@ -112,7 +115,16 @@ void Director::Execute(std::shared_ptr<CancellationToken> executionCancellationT
|
|||
}
|
||||
}
|
||||
|
||||
this->CancelNextExecution();
|
||||
this->StopExecution();
|
||||
}
|
||||
|
||||
void Director::StopExecution()
|
||||
{
|
||||
if (this->m_executionCancellationToken.get() != nullptr)
|
||||
{
|
||||
this->m_executionCancellationToken->Cancel();
|
||||
this->m_executionCancellationToken = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
long long Director::GetNextQueuedExecutionTime() const
|
||||
|
@ -130,7 +142,7 @@ long long Director::GetNextQueuedExecutionTime() const
|
|||
void Director::ScheduleNextExecution()
|
||||
{
|
||||
long long executionDelayInMilliseconds = std::max<long long>(this->m_nextScheduledExecutionTime - PosixUtcInMilliseconds(), 0LL);
|
||||
this->m_currentExecutionCancellationToken = std::make_shared<CancellationToken>();
|
||||
this->m_executionCancellationToken = std::make_shared<CancellationToken>();
|
||||
auto executionPromise = std::make_unique<std::promise<bool>>();
|
||||
this->m_executionResult = std::make_shared<std::future<bool>>(executionPromise->get_future());
|
||||
|
||||
|
@ -140,7 +152,13 @@ void Director::ScheduleNextExecution()
|
|||
retry = false;
|
||||
try
|
||||
{
|
||||
std::thread executionThread(&Director::ExecuteInternal, this->shared_from_this(), executionDelayInMilliseconds, std::move(executionPromise), this->m_currentExecutionCancellationToken);
|
||||
std::thread executionThread(
|
||||
&Director::ExecuteInternal,
|
||||
this,
|
||||
executionDelayInMilliseconds,
|
||||
std::move(executionPromise),
|
||||
this->m_executionCancellationToken);
|
||||
|
||||
executionThread.detach();
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
|
@ -157,15 +175,6 @@ void Director::ScheduleNextExecution()
|
|||
} while (retry);
|
||||
}
|
||||
|
||||
void Director::CancelNextExecution()
|
||||
{
|
||||
if (this->m_currentExecutionCancellationToken.get() != nullptr)
|
||||
{
|
||||
this->m_currentExecutionCancellationToken->Cancel();
|
||||
this->m_currentExecutionCancellationToken = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Director::ExecuteInternal(long long executionDelayInMilliseconds, std::unique_ptr<std::promise<bool>> executionPromise, std::shared_ptr<CancellationToken> cancellationToken)
|
||||
{
|
||||
if (executionDelayInMilliseconds != 0LL)
|
||||
|
@ -330,7 +339,7 @@ bool Director::NeedsReset() const
|
|||
|
||||
void Director::Reset()
|
||||
{
|
||||
this->CancelNextExecution();
|
||||
this->StopExecution();
|
||||
this->m_callbackQueue.clear();
|
||||
this->m_scheduledCallbacks.clear();
|
||||
this->m_nextCallbackId = 0;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
// callbacks to be executed synchronously while making it appear to the accessors as if they execute atomically and
|
||||
// concurrently, enabling asynchronous yet coordinated reactions without explicit thread management or locks.
|
||||
//
|
||||
class Director : public std::enable_shared_from_this<Director>
|
||||
class Director
|
||||
{
|
||||
public:
|
||||
Director();
|
||||
|
@ -37,7 +37,8 @@ public:
|
|||
|
||||
void ClearScheduledCallback(int callbackId);
|
||||
void HandlePriorityUpdate(int oldPriority, int newPriority);
|
||||
void Execute(std::shared_ptr<CancellationToken> executionCancellationToken, int numberOfIterations = 0);
|
||||
void Execute(int numberOfIterations = 0);
|
||||
void StopExecution();
|
||||
|
||||
private:
|
||||
class ScheduledCallback
|
||||
|
@ -52,7 +53,6 @@ private:
|
|||
|
||||
long long GetNextQueuedExecutionTime() const;
|
||||
void ScheduleNextExecution();
|
||||
void CancelNextExecution();
|
||||
void ExecuteInternal(
|
||||
long long executionDelayInMilliseconds,
|
||||
std::unique_ptr<std::promise<bool>> executionPromise,
|
||||
|
@ -72,7 +72,7 @@ private:
|
|||
long long m_startTime;
|
||||
long long m_nextScheduledExecutionTime;
|
||||
std::shared_ptr<std::future<bool>> m_executionResult;
|
||||
std::shared_ptr<CancellationToken> m_currentExecutionCancellationToken;
|
||||
std::shared_ptr<CancellationToken> m_executionCancellationToken;
|
||||
|
||||
static long long PosixUtcInMilliseconds();
|
||||
};
|
||||
|
|
|
@ -14,14 +14,18 @@ static const int HostPriority = UpdateModelPriority + 1;
|
|||
Host::Impl::Impl(const std::string& name, Host* container, std::function<void(Accessor&)> initializeFunction) :
|
||||
CompositeAccessor::Impl(name, container, initializeFunction),
|
||||
m_state(Host::State::NeedsSetup),
|
||||
m_director(std::make_shared<Director>()),
|
||||
m_executionCancellationToken(nullptr),
|
||||
m_director(std::make_unique<Director>()),
|
||||
m_nextListenerId(0)
|
||||
{
|
||||
this->m_priority = HostPriority;
|
||||
}
|
||||
|
||||
Host::Impl::~Impl() = default;
|
||||
Host::Impl::~Impl()
|
||||
{
|
||||
this->RemoveAllChildren();
|
||||
this->ClearAllScheduledCallbacks();
|
||||
this->m_director.reset(nullptr);
|
||||
}
|
||||
|
||||
Host::State Host::Impl::GetState() const
|
||||
{
|
||||
|
@ -64,11 +68,10 @@ void Host::Impl::Iterate(int numberOfIterations)
|
|||
{
|
||||
this->ValidateHostCanRun();
|
||||
this->SetState(Host::State::Running);
|
||||
this->m_executionCancellationToken = std::make_shared<CancellationToken>();
|
||||
|
||||
try
|
||||
{
|
||||
this->m_director->Execute(this->m_executionCancellationToken, numberOfIterations);
|
||||
this->m_director->Execute(numberOfIterations);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -86,8 +89,7 @@ void Host::Impl::Pause()
|
|||
throw std::logic_error("Host is not running");
|
||||
}
|
||||
|
||||
this->m_executionCancellationToken->Cancel();
|
||||
this->m_executionCancellationToken = nullptr;
|
||||
this->m_director->StopExecution();
|
||||
this->SetState(Host::State::Paused);
|
||||
}
|
||||
|
||||
|
@ -120,11 +122,10 @@ void Host::Impl::RunOnCurrentThread()
|
|||
{
|
||||
this->ValidateHostCanRun();
|
||||
this->SetState(Host::State::Running);
|
||||
this->m_executionCancellationToken = std::make_shared<CancellationToken>();
|
||||
|
||||
try
|
||||
{
|
||||
this->m_director->Execute(this->m_executionCancellationToken);
|
||||
this->m_director->Execute();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -138,12 +139,7 @@ void Host::Impl::RunOnCurrentThread()
|
|||
void Host::Impl::Exit()
|
||||
{
|
||||
this->SetState(Host::State::Exiting);
|
||||
if (this->m_executionCancellationToken.get() != nullptr)
|
||||
{
|
||||
this->m_executionCancellationToken->Cancel();
|
||||
this->m_executionCancellationToken = nullptr;
|
||||
}
|
||||
|
||||
this->m_director->StopExecution();
|
||||
this->SetState(Host::State::Finished);
|
||||
}
|
||||
|
||||
|
@ -196,9 +192,9 @@ void Host::Impl::ResetPriority()
|
|||
this->ResetChildrenPriorities();
|
||||
}
|
||||
|
||||
std::shared_ptr<Director> Host::Impl::GetDirector() const
|
||||
Director* Host::Impl::GetDirector() const
|
||||
{
|
||||
return this->m_director->shared_from_this();
|
||||
return this->m_director.get();
|
||||
}
|
||||
|
||||
void Host::Impl::ValidateHostCanRun() const
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#define HOST_IMPL_H
|
||||
|
||||
#include "AccessorFramework/Host.h"
|
||||
#include "CancellationToken.h"
|
||||
#include "CompositeAccessorImpl.h"
|
||||
#include "Director.h"
|
||||
#include <atomic>
|
||||
|
@ -32,7 +31,7 @@ public:
|
|||
Impl(const std::string& name, Host* container, std::function<void(Accessor&)> initializeFunction);
|
||||
~Impl();
|
||||
void ResetPriority() override;
|
||||
std::shared_ptr<Director> GetDirector() const override;
|
||||
Director* GetDirector() const override;
|
||||
|
||||
protected:
|
||||
// Host Methods
|
||||
|
@ -85,8 +84,7 @@ private:
|
|||
void NotifyListenersOfStateChange(Host::State oldState, Host::State newState);
|
||||
|
||||
std::atomic<Host::State> m_state;
|
||||
std::shared_ptr<Director> m_director;
|
||||
std::shared_ptr<CancellationToken> m_executionCancellationToken;
|
||||
std::unique_ptr<Director> m_director;
|
||||
std::map<int, std::weak_ptr<Host::EventListener>> m_listeners;
|
||||
int m_nextListenerId;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче