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:
Fischlurch 2023-10-12 20:23:59 +02:00
parent 184c93750a
commit 1ffee39b23
8 changed files with 149 additions and 98 deletions

View file

@ -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);

View file

@ -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());
}

View file

@ -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(); }
};

View file

@ -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

View file

@ -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<>

View file

@ -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

View file

@ -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&#xe4;nzung: autonomous Thread">
<node COLOR="#338800" CREATED="1696468379848" FOLDED="true" ID="ID_1146069423" MODIFIED="1697133540550" TEXT="Erg&#xe4;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&#xf6;sen">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1696893013891" ID="ID_1856740667" MODIFIED="1697133524821" TEXT="damit bestehende Probleme im Applikations-Code l&#xf6;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:&#160;&#160;&#160;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:&#160;&#160;&#160;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:&#160;&#160;&#160;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:&#160;&#160;&#160;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 &#xfc;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:&#160;&#160;&#160;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&#xe4;be es eine L&#xfc;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:&#160;&#160;&#160;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&#xf6;sung f&#xfc;r dieses Nutz-Muster">
<node COLOR="#338800" CREATED="1696539035824" ID="ID_1472214443" MODIFIED="1697133350320" TEXT="generische L&#xf6;sung f&#xfc;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:&#160;&#160;&#160;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&#xdf; 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&#xe4;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&#xe4;ren">
<icon BUILTIN="button_ok"/>
<node CREATED="1697128200944" ID="ID_1946980837" MODIFIED="1697128216272" TEXT="in diesem Fall mu&#xdf; es ein Lifecycle-Hook sein"/>
<node CREATED="1697128241409" ID="ID_383238232" MODIFIED="1697128271254">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
au&#223;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&#223; <b>zwingend</b>&#160;<font face="Monospaced" color="#341189">detach()</font>&#160;aufgerufen werden &#8212; <i>hier</i>&#160; und <i>nicht</i>&#160;im Destruktor
</p>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Und zwar addressiert das hier das subtile Problem, da&#223; der umschlie&#223;ende Kontext auch auf au&#223;ergew&#246;hnlichem Weg und vorzeitig zerst&#246;rt werden kann, obwohl der Thread noch l&#228;uft. Daher ist es w&#252;nschenswert, da&#223; 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&#xf6;sung: &#x3bb;-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 &#x3bb; gebunden werden, das den Pointer am Ende wieder leert"/>
<node CREATED="1697129347357" ID="ID_230048402" MODIFIED="1697129378773" TEXT="aber im DispatcherLoop-Objekt wird dieses &#x3bb; in das eigentliche hook-&#x3bb; gepackt"/>
<node CREATED="1697129379529" ID="ID_1027277309" MODIFIED="1697129395410" TEXT="denn dieses nimmt eine ThreadWrapper-Instanz, um darauf detach() aufrufen zu k&#xf6;nnen"/>
<node CREATED="1697129400411" ID="ID_968891728" MODIFIED="1697129448246" TEXT="detach() habe ich bewu&#xdf;t protected gemacht &#x27fc; 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&#xfc;ckbau alter code">
<icon BUILTIN="hourglass"/>
</node>
</node>
</node>
</node>
</node>