LibraryApplication: tie DispatcherLoop to thread lifecycle
This solution is basically equivalent to the version implemented directly, but uses the lifecycle-Hooks available through `ThreadHookable` to structure the code and separate the concerns better. This largely completes the switch to the new thread-wrapper.. **the old implementation is not referenced anymore**
This commit is contained in:
parent
184c93750a
commit
1ffee39b23
8 changed files with 149 additions and 98 deletions
|
|
@ -183,7 +183,11 @@ namespace lumiera {
|
|||
INFO (subsystem, "Triggering startup of subsystem \"%s\"", cStr(*susy));
|
||||
|
||||
for_each (susy->getPrerequisites(), start_);
|
||||
bool started = susy->start (opts_, bind (&SubsystemRunner::sigTerm, this, susy, _1));
|
||||
bool started = susy->start (opts_, [this,susy]
|
||||
(string* problem)
|
||||
{
|
||||
this->sigTerm (susy, problem);
|
||||
});
|
||||
|
||||
if (started)
|
||||
{
|
||||
|
|
@ -204,9 +208,9 @@ namespace lumiera {
|
|||
{
|
||||
REQUIRE (susy);
|
||||
Lock sync (this);
|
||||
triggerEmergency(!isnil (problem));
|
||||
triggerEmergency(not isnil (problem));
|
||||
INFO (subsystem, "Subsystem '%s' terminated.", cStr(*susy));
|
||||
WARN_IF (!isnil(problem), subsystem, "Irregular shutdown caused by: %s", cStr(*problem));
|
||||
WARN_IF (not isnil(problem), subsystem, "Irregular shutdown caused by: %s", cStr(*problem));
|
||||
ERROR_IF (susy->isRunning(), subsystem, "Subsystem '%s' signals termination, "
|
||||
"without resetting running state", cStr(*susy));
|
||||
removeall (running_, susy);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace thread{
|
|||
void
|
||||
ThreadWrapper::markThreadEnd()
|
||||
{
|
||||
TRACE (thread, "%s", lifecycleMsg ("finished.", threadID_).c_str());
|
||||
TRACE (thread, "%s", lifecycleMsg ("terminates.", threadID_).c_str());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -270,8 +270,7 @@ namespace lib {
|
|||
void
|
||||
handle_after_thread()
|
||||
{
|
||||
if (BAS::isLive())
|
||||
BAS::threadImpl_.detach();
|
||||
BAS::detach_thread_from_wrapper();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -316,8 +315,8 @@ namespace lib {
|
|||
{
|
||||
if (hook_afterThread)
|
||||
hook_afterThread (*this);
|
||||
if (BAS::isLive()) // Note: ensure thread is detached at end
|
||||
BAS::threadImpl_.detach();
|
||||
// Note: ensure thread is detached at end
|
||||
BAS::detach_thread_from_wrapper();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -649,16 +648,6 @@ namespace lib {
|
|||
{
|
||||
public:
|
||||
using ThreadLifecycle::ThreadLifecycle;
|
||||
|
||||
/** allow to detach explicitly — independent from thread-function's state
|
||||
* @warning this function is borderline dangerous; it might be acceptable
|
||||
* in a situation where the thread totally manages itself and the
|
||||
* thread object is maintained in a unique_ptr. You must ensure that
|
||||
* the thread function only uses storage within its own scope.
|
||||
* @deprecated can't sleep well while this function is exposed;
|
||||
* need a prime solution to address this relevant use case ////////////////////////////////////////OOO allow for a thread with explicit lifecycle
|
||||
*/
|
||||
void detach() { ThreadLifecycle::handle_after_thread(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
** The SteamDispatcher is at the heart of the session subsystem and implements a
|
||||
** (single) session thread to perform commands and trigger builder runs. New commands
|
||||
** can be enqueued with a dedicated CommandQueue, while the details of operation control
|
||||
** logic are encapsulated in a [logic component](\ref Looper).
|
||||
** logic are encapsulated in a [processing logic component](\ref Looper).
|
||||
**
|
||||
** # Operational Semantics
|
||||
** We need to distinguish between the SteamDispatcher itself, which is a static (singleton) service,
|
||||
|
|
@ -34,15 +34,15 @@
|
|||
** while the Session itself is a data structure and can be closed, opened or re-loaded. There is a singular
|
||||
** transactional access point to the Session datastructure, which can be switched to new session contents.
|
||||
** But external manipulation of the session contents is performed by commands, which are _dispatched_ --
|
||||
** to manage this process is the concern of the »Session Subsystem«.
|
||||
** and the management of this process is the concern served by the »Session Subsystem«.
|
||||
**
|
||||
** Closing a session blocks further command processing, while the lifecycle of the _Session Subsystem_ is
|
||||
** actually linked to _running the \ref DispatcherLoop_ -- implementation logic defined within this
|
||||
** translation unit. This loop implementation is performed in a dedicated thread, _the Session Loop Thread._
|
||||
** actually linked to _running the \ref DispatcherLoop_ -- a piece of implementation logic defined within this
|
||||
** translation unit. The loop implementation is performed within a dedicated thread, _the Session Loop Thread._
|
||||
** And this also entails opening the public SessionCommandService interface.
|
||||
**
|
||||
** ## Loop operation control
|
||||
** The loop starts with a blocking wait state, bound to the condition Looper::requireAction. Here, Looper
|
||||
** The loop starts with a blocking wait state, bound to the condition Looper::requireAction. The Looper
|
||||
** is a helper to encapsulate the control logic, separated from the actual control flow. In the loop body,
|
||||
** depending on the Looper's decision, either the next command is fetched from the CommandQueue and dispatched,
|
||||
** or a builder run is triggered, rebuilding the »Low-Level-Model« to reflect the executed command's effects.
|
||||
|
|
@ -53,21 +53,21 @@
|
|||
** - yet we continue to dispatch further commands, until the queue is emptied
|
||||
** - and only after a further small latency wait, the builder run is triggered
|
||||
** - but we _enforce a builder run_ after some extended timeout period, even
|
||||
** when the command queue is not yet emptied
|
||||
** when the command queue is not emptied yet
|
||||
** - from the outside, it is possible to deactivate processing and place the
|
||||
** loop into dormant state. This is used while closing or loading the Session
|
||||
** - and of course we can request the Session Loop Thread to stop, for shutting
|
||||
** down the »Session Subsystem« as a whole
|
||||
** - in both cases the currently performed action (command or builder) is
|
||||
** finished, without interrupt
|
||||
** finished, without interruption.
|
||||
**
|
||||
** ## Locking
|
||||
** The SteamDispatcher uses an "inner and outer capsule" design, and both layers are locked independently.
|
||||
** On the outer layer, locking ensures sanity of the control data structures, while locking on the inner
|
||||
** layer guards the communication with the Session Loop Thread, and coordinates sleep wait and notification.
|
||||
** As usual with Lumiera's Thread wrapper, the management of the thread's lifecycle itself, hand-over of
|
||||
** parameters, and starting / joining of the thread operation is protected by separate locking embedded
|
||||
** into the thread and threadpool handling code.
|
||||
** parameters, and starting / joining of the thread operation is protected by means of synchronisation
|
||||
** embedded into the underlying implementation (C++ standard library thread support).
|
||||
** @note most of the time, the Session Loop Thread does not hold any lock, most notably while performing
|
||||
** a command or running the builder. Likewise, evaluation of the control logic in the Looper helper
|
||||
** is a private detail of the performing thread. The lock is acquired solely for checking or leaving
|
||||
|
|
@ -93,13 +93,15 @@
|
|||
#include "lib/thread.hpp"
|
||||
#include "lib/util.hpp" ///////////////TODO for test command invocation
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
using lib::Sync;
|
||||
using lib::RecursiveLock_Waitable;
|
||||
using lib::SyncBarrier;
|
||||
using lib::Thread;
|
||||
using std::unique_ptr;
|
||||
using lib::ThreadHookable;
|
||||
using lib::RecursiveLock_Waitable;
|
||||
using std::make_unique;
|
||||
using std::move;
|
||||
|
||||
namespace steam {
|
||||
namespace control {
|
||||
|
|
@ -119,14 +121,16 @@ namespace control {
|
|||
, public Sync<RecursiveLock_Waitable>
|
||||
{
|
||||
using ServiceHandle = lib::DependInject<SessionCommandService>::ServiceInstance<>;
|
||||
using Launch = lib::ThreadHookable::Launch;
|
||||
|
||||
/** manage the primary public Session interface */
|
||||
ServiceHandle commandService_;
|
||||
|
||||
SyncBarrier init_;
|
||||
CommandQueue queue_;
|
||||
string error_;
|
||||
Looper looper_;
|
||||
Thread thread_;
|
||||
ThreadHookable thread_;
|
||||
|
||||
public:
|
||||
/** start the session loop thread
|
||||
|
|
@ -137,16 +141,24 @@ namespace control {
|
|||
* in case it does, the main application thread will be deadlocked on startup.
|
||||
* Such might happen indirectly, when something depends on "the Session"
|
||||
*/
|
||||
DispatcherLoop (Subsys::SigTerm notification)
|
||||
template<typename FUN>
|
||||
DispatcherLoop (FUN&& atExit)
|
||||
: commandService_{ServiceHandle::NOT_YET_STARTED}
|
||||
, queue_{}
|
||||
, error_{}
|
||||
, looper_([&]() -> bool
|
||||
{
|
||||
return not queue_.empty();
|
||||
})
|
||||
, thread_{"Session"
|
||||
,&DispatcherLoop::runSessionThread
|
||||
, this, notification}
|
||||
, thread_{ //----the-Session-Thread---------------
|
||||
Launch{&DispatcherLoop::runSessionThread, this}
|
||||
.threadID("Session")
|
||||
.atExit([this, signalEndOfThread = move(atExit)]
|
||||
(lib::thread::ThreadWrapper& handle)
|
||||
{
|
||||
handle.detach_thread_from_wrapper();
|
||||
signalEndOfThread (&error_);
|
||||
})}
|
||||
{
|
||||
init_.sync(); // done with setup; loop may run now....
|
||||
INFO (session, "Steam-Dispatcher running...");
|
||||
|
|
@ -161,6 +173,8 @@ namespace control {
|
|||
try {
|
||||
commandService_.shutdown(); // redundant call, to ensure session interface is closed reliably
|
||||
INFO (session, "Steam-Dispatcher stopped.");
|
||||
if (thread_)
|
||||
ALERT (session, "Dispatcher destroyed while Session thread is running. The rest is silence.");
|
||||
}
|
||||
ERROR_LOG_AND_IGNORE(session, "Stopping the Steam-Dispatcher");
|
||||
}
|
||||
|
|
@ -235,9 +249,8 @@ namespace control {
|
|||
* to invoke SteamDispatcher::endRunningLoopState().
|
||||
*/
|
||||
void
|
||||
runSessionThread (Subsys::SigTerm notifyEnd)
|
||||
runSessionThread ()
|
||||
{
|
||||
string errorMsg;
|
||||
init_.sync();
|
||||
try
|
||||
{
|
||||
|
|
@ -256,18 +269,15 @@ namespace control {
|
|||
}
|
||||
catch (std::exception& problem)
|
||||
{ // could also be lumiera::Error
|
||||
errorMsg = problem.what();
|
||||
error_ = problem.what();
|
||||
lumiera_error(); // clear error flag
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
errorMsg = string{lumiera_error()};
|
||||
}
|
||||
// leave the Session thread...
|
||||
// send notification of subsystem shutdown
|
||||
thread_.detach();/////////////////////////////////////////////////////////////OOO while this case is exceptional, it still mandates better framework support
|
||||
notifyEnd (&errorMsg); // invokes ~DispatcherLoop()
|
||||
error_ = string{lumiera_error()};
|
||||
}
|
||||
// Session thread terminates...
|
||||
} // atExit-λ will invoke ~DispatcherLoop()
|
||||
|
||||
void
|
||||
awaitAction() ///< at begin of loop body...
|
||||
|
|
@ -354,19 +364,41 @@ namespace control {
|
|||
Lock sync(this);
|
||||
if (runningLoop_) return false;
|
||||
|
||||
runningLoop_.reset (
|
||||
new DispatcherLoop (
|
||||
[=] (string* problemMessage)
|
||||
{
|
||||
runningLoop_ =
|
||||
make_unique<DispatcherLoop>(
|
||||
[=](string* problemIndicator)
|
||||
{ // when the Session thread ends....
|
||||
SteamDispatcher::endRunningLoopState();
|
||||
termNotification(problemMessage);
|
||||
}));
|
||||
termNotification (problemIndicator);
|
||||
});
|
||||
|
||||
if (active_)
|
||||
runningLoop_->activateCommandProecssing();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @internal clean-up when leaving the session loop thread.
|
||||
* This function is hooked up in to the termination callback,
|
||||
* and is in fact the only one to delete the loop PImpl. We
|
||||
* take the (outer) lock on SteamDispatcher to ensure no one
|
||||
* commits anything to the DispatcherLoop object while being
|
||||
* deleted. The call itself, while technically originating
|
||||
* from within DispatcherLoop::runSessionThread(), relies
|
||||
* solely on stack based context data and is a tail call.
|
||||
*/
|
||||
void
|
||||
SteamDispatcher::endRunningLoopState()
|
||||
{
|
||||
Lock sync(this);
|
||||
if (runningLoop_)
|
||||
runningLoop_.reset(); // delete DispatcherLoop object
|
||||
else
|
||||
WARN (command, "clean-up of DispatcherLoop invoked, "
|
||||
"while SteamDispatcher is not marked as 'running'. "
|
||||
"Likely an error in lifecycle logic, as the only one "
|
||||
"intended to delete this object is the loop thread itself.");
|
||||
}
|
||||
|
||||
|
||||
/** whether the »session subsystem« is operational.
|
||||
* @return `true` if the session loop thread has been fully
|
||||
|
|
@ -395,28 +427,6 @@ namespace control {
|
|||
}
|
||||
|
||||
|
||||
/** @internal clean-up when leaving the session loop thread.
|
||||
* This function is hooked up in to the termination callback,
|
||||
* and is in fact the only one to delete the loop PImpl. We
|
||||
* take the (outer) lock on SteamDispatcher to ensure no one
|
||||
* commits anything to the DispatcherLoop object while being
|
||||
* deleted. The call itself, while technically originating
|
||||
* from within DispatcherLoop::runSessionThread(), relies
|
||||
* solely on stack based context data and is a tail call.
|
||||
*/
|
||||
void
|
||||
SteamDispatcher::endRunningLoopState()
|
||||
{
|
||||
Lock sync(this);
|
||||
if (runningLoop_)
|
||||
runningLoop_.reset(); // delete DispatcherLoop object
|
||||
else
|
||||
WARN (command, "clean-up of DispatcherLoop invoked, "
|
||||
"while SteamDispatcher is not marked as 'running'. "
|
||||
"Likely an error in lifecycle logic, as the only one "
|
||||
"intended to delete this object is the loop thread itself.");
|
||||
}
|
||||
|
||||
|
||||
/** activate processing of enqueued session commands.
|
||||
* @remarks command processing serves as public external interface
|
||||
|
|
|
|||
|
|
@ -73,13 +73,15 @@ namespace control {
|
|||
|
||||
|
||||
/**
|
||||
* Guard to manage processing commands working on the session.
|
||||
* Guard to manage processing commands to operate on the session.
|
||||
* A static application facility, actually backing and implementing
|
||||
* the »session subsystem«. Embedded within the implementation of this
|
||||
* class is the _»session loop thread«_ to perform any session mutation
|
||||
* commands and to operate the Builder, which translates the session
|
||||
* commands and to activate the Builder, which translates the session
|
||||
* contents into a render nodes network. Also embedded herein is
|
||||
* the implementation of steam::control::SessionCommandService
|
||||
* @warning destroying this object while #isRunning() will
|
||||
* terminate the Application unconditionally.
|
||||
*/
|
||||
class SteamDispatcher
|
||||
: public lib::Sync<>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
PLANNED "Detect Thread lifecycle state changes" ThreadWrapperLifecycle_test <<END
|
||||
TEST "Detect Thread lifecycle state changes" ThreadWrapperLifecycle_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -65009,9 +65009,9 @@
|
|||
<node COLOR="#338800" CREATED="1695597447169" ID="ID_35947260" MODIFIED="1695859231223" TEXT="Fehlerbehandlung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1696468379848" ID="ID_1146069423" MODIFIED="1697054187170" TEXT="Ergänzung: autonomous Thread">
|
||||
<node COLOR="#338800" CREATED="1696468379848" FOLDED="true" ID="ID_1146069423" MODIFIED="1697133540550" TEXT="Ergänzung: autonomous Thread">
|
||||
<linktarget COLOR="#5a83aa" DESTINATION="ID_1146069423" ENDARROW="Default" ENDINCLINATION="444;909;" ID="Arrow_ID_516910789" SOURCE="ID_137837629" STARTARROW="None" STARTINCLINATION="-1280;-32;"/>
|
||||
<icon BUILTIN="pencil"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1696468398477" ID="ID_1775921981" MODIFIED="1696966299356" TEXT="neue Anforderung: komplett abgekoppelt">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1696468424018" ID="ID_1127252428" MODIFIED="1696468584146" TEXT="ergibt sich aus dem Protokoll der C++14 - Threads">
|
||||
|
|
@ -66291,8 +66291,8 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1696893013891" ID="ID_1856740667" MODIFIED="1697068782982" TEXT="damit bestehende Probleme im Applikations-Code lösen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1696893013891" ID="ID_1856740667" MODIFIED="1697133524821" TEXT="damit bestehende Probleme im Applikations-Code lösen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1696893026770" ID="ID_253995958" MODIFIED="1697079847058" TEXT="GtkLumiera">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1696893056374" MODIFIED="1696893056374" TEXT="Variante-1"/>
|
||||
|
|
@ -66301,7 +66301,8 @@
|
|||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1696893058148" MODIFIED="1696893058148" TEXT="Variante-1"/>
|
||||
</node>
|
||||
<node CREATED="1696893032057" ID="ID_926131453" MODIFIED="1696893046381" TEXT="SteamDispatcher">
|
||||
<node COLOR="#338800" CREATED="1696893032057" ID="ID_926131453" MODIFIED="1697133522544" TEXT="SteamDispatcher">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1696893059260" ID="ID_109825250" MODIFIED="1696893063103" TEXT="Variante-2"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -82276,9 +82277,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695394237210" ID="ID_11553358" MODIFIED="1696029630733" TEXT="Applikation umstellen">
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1695394237210" ID="ID_11553358" MODIFIED="1697133471895" TEXT="Applikation umstellen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<icon BUILTIN="pencil"/>
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node CREATED="1696029414385" ID="ID_140265798" MODIFIED="1696029417676" TEXT="weitere Tests...">
|
||||
<node COLOR="#338800" CREATED="1696029465122" ID="ID_1515483274" MODIFIED="1696357491529" TEXT="SubsystemRunner_test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -82465,7 +82467,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1696029465121" ID="ID_786350998" MODIFIED="1697079789466" TEXT="gtk-lumiera.cpp">
|
||||
<node COLOR="#338800" CREATED="1696029465121" FOLDED="true" ID="ID_786350998" MODIFIED="1697079789466" TEXT="gtk-lumiera.cpp">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1696468041645" ID="ID_137837629" MODIFIED="1697079810297" TEXT="brauche einen Thread, den man in den Hintergrund schieben kann">
|
||||
<arrowlink COLOR="#5a83aa" DESTINATION="ID_1146069423" ENDARROW="Default" ENDINCLINATION="444;909;" ID="Arrow_ID_516910789" STARTARROW="None" STARTINCLINATION="-1280;-32;"/>
|
||||
|
|
@ -82529,7 +82531,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<arrowlink COLOR="#1f9fe7" DESTINATION="ID_871343805" ENDARROW="Default" ENDINCLINATION="173;10;" ID="Arrow_ID_1685700346" STARTARROW="None" STARTINCLINATION="-8;8;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1696029465122" ID="ID_871343805" MODIFIED="1697068873667" TEXT="output-director.cpp">
|
||||
<node COLOR="#338800" CREATED="1696029465122" FOLDED="true" ID="ID_871343805" MODIFIED="1697068873667" TEXT="output-director.cpp">
|
||||
<linktarget COLOR="#1f9fe7" DESTINATION="ID_871343805" ENDARROW="Default" ENDINCLINATION="173;10;" ID="Arrow_ID_1685700346" SOURCE="ID_1299573982" STARTARROW="None" STARTINCLINATION="-8;8;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696888656242" HGAP="36" ID="ID_1500509085" MODIFIED="1696888747350" STYLE="fork" TEXT="Symptom hier: bad_alloc im Shutdown" VSHIFT="25">
|
||||
|
|
@ -82542,15 +82544,15 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5a3" COLOR="#883300" CREATED="1696029465122" ID="ID_556208204" MODIFIED="1696539012684" TEXT="steam-dispatcher.cpp">
|
||||
<node COLOR="#338800" CREATED="1696029465122" FOLDED="true" ID="ID_556208204" MODIFIED="1697133495447" TEXT="steam-dispatcher.cpp">
|
||||
<linktarget COLOR="#71be6f" DESTINATION="ID_556208204" ENDARROW="Default" ENDINCLINATION="1038;-401;" ID="Arrow_ID_1257115855" SOURCE="ID_1718267866" STARTARROW="None" STARTINCLINATION="602;40;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1696039703074" ID="ID_796238065" MODIFIED="1696171045349" TEXT="Refactoring wie üblich">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1696039723008" ID="ID_932291373" MODIFIED="1696039728651" TEXT="Thread wird ein Member-Feld"/>
|
||||
<node CREATED="1696039729255" ID="ID_249325323" MODIFIED="1696039735587" TEXT="Sync-Barrier kommt hinzu"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1696171047044" ID="ID_964609053" MODIFIED="1696179878653" TEXT="Problem beim Shutdown">
|
||||
<node COLOR="#435e98" CREATED="1696171047044" FOLDED="true" ID="ID_964609053" MODIFIED="1696179878653" TEXT="Problem beim Shutdown">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696171082115" ID="ID_150270315" MODIFIED="1696171100640" TEXT="Session-Thread endet nicht rechtzeitig">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -82630,6 +82632,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
<node CREATED="1696174292902" ID="ID_866561914" MODIFIED="1696174342106" TEXT="aber vom SteamDispatcher-dtor gäbe es eine Lücke">
|
||||
<linktarget COLOR="#7c8d9d" DESTINATION="ID_866561914" ENDARROW="Default" ENDINCLINATION="-348;479;" ID="Arrow_ID_1571953987" SOURCE="ID_1682021227" STARTARROW="None" STARTINCLINATION="-215;7;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1696174343863" ID="ID_210073839" MODIFIED="1696174470614" TEXT="ebenfalls ehr unwahrscheinlich (Singleton!)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -82719,9 +82722,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696539035824" ID="ID_1472214443" MODIFIED="1696539109792" TEXT="generische Lösung für dieses Nutz-Muster">
|
||||
<node COLOR="#338800" CREATED="1696539035824" ID="ID_1472214443" MODIFIED="1697133350320" TEXT="generische Lösung für dieses Nutz-Muster">
|
||||
<linktarget COLOR="#696992" DESTINATION="ID_1472214443" ENDARROW="Default" ENDINCLINATION="-24;-75;" ID="Arrow_ID_409292846" SOURCE="ID_1071243890" STARTARROW="None" STARTINCLINATION="-43;3;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1696539114617" ID="ID_104020495" MODIFIED="1696620523042" TEXT="ThreadHookable">
|
||||
<arrowlink COLOR="#898bab" DESTINATION="ID_1917558827" ENDARROW="Default" ENDINCLINATION="-1027;99;" ID="Arrow_ID_1553665185" STARTARROW="None" STARTINCLINATION="532;77;"/>
|
||||
<icon BUILTIN="info"/>
|
||||
|
|
@ -82729,18 +82732,61 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696539286066" ID="ID_53739973" MODIFIED="1696539300376" TEXT="bestehenden Code in DispatcherLoop umschreiben">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1696539286066" ID="ID_53739973" MODIFIED="1697133342508" TEXT="bestehenden Code in DispatcherLoop umschreiben">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1696539301472" ID="ID_938150628" MODIFIED="1696539312778" TEXT="sollte weitgehend ein drop-in-replacement sein"/>
|
||||
<node CREATED="1696539313368" ID="ID_1530319321" MODIFIED="1696539338246" TEXT="nur daß nun keine Heap-Allokation mehr stattfindet"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696539414089" ID="ID_1532143583" MODIFIED="1696539433399" TEXT="Problem mit geeigneter Wrapper-Basisklasse klären">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1696539313368" ID="ID_1530319321" MODIFIED="1697124202275" TEXT="auch die Allokation erfolgt wie bisher direkt in den unique-ptr"/>
|
||||
<node COLOR="#338800" CREATED="1696539414089" ID="ID_1532143583" MODIFIED="1697133332702" TEXT="Problem mit geeigneter Wrapper-Basisklasse klären">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1697128200944" ID="ID_1946980837" MODIFIED="1697128216272" TEXT="in diesem Fall muß es ein Lifecycle-Hook sein"/>
|
||||
<node CREATED="1697128241409" ID="ID_383238232" MODIFIED="1697128271254">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
außerdem ist das thread-Objekt (nach dem Refactoring) nur noch <i>Member</i>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1697128310456" ID="ID_1682021227" MODIFIED="1697128572722">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
zudem muß <b>zwingend</b> <font face="Monospaced" color="#341189">detach()</font> aufgerufen werden — <i>hier</i>  und <i>nicht</i> im Destruktor
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Und zwar addressiert das hier das subtile Problem, daß der umschließende Kontext auch auf außergewöhnlichem Weg und vorzeitig zerstört werden kann, obwohl der Thread noch läuft. Daher ist es wünschenswert, daß der Destruktor bei noch laufendem Thread die Applikation hart terminiert
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#7c8d9d" DESTINATION="ID_866561914" ENDARROW="Default" ENDINCLINATION="-348;479;" ID="Arrow_ID_1571953987" STARTARROW="None" STARTINCLINATION="-215;7;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697128673738" ID="ID_1921134580" MODIFIED="1697133338424" TEXT="Lösung: λ-Kette">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1697128706291" ID="ID_177194465" MODIFIED="1697128761575" TEXT="der TerminationSignal-Funktor steht dort bereit, wo auch die DispatcherLoop konstruiert wird"/>
|
||||
<node CREATED="1697128762283" ID="ID_743745630" MODIFIED="1697128801666" TEXT="genau dort sollte auch ein λ gebunden werden, das den Pointer am Ende wieder leert"/>
|
||||
<node CREATED="1697129347357" ID="ID_230048402" MODIFIED="1697129378773" TEXT="aber im DispatcherLoop-Objekt wird dieses λ in das eigentliche hook-λ gepackt"/>
|
||||
<node CREATED="1697129379529" ID="ID_1027277309" MODIFIED="1697129395410" TEXT="denn dieses nimmt eine ThreadWrapper-Instanz, um darauf detach() aufrufen zu können"/>
|
||||
<node CREATED="1697129400411" ID="ID_968891728" MODIFIED="1697129448246" TEXT="detach() habe ich bewußt protected gemacht ⟼ detach_thread_from_wrapper()">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1697133453673" ID="ID_1053950423" MODIFIED="1697133470456" TEXT="Rückbau alter code">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue