Library: still fighting to get the design straight

Considering a solution to shift the actual launch of the new thread
from the initialiser list into the ctor body, to circumvent the possible
"undefined behaviour". This would also be prerequisite for defining
a self-managed variant of the thread-wrapper.

Alternative / Plan.B would be to abandon the idea of a self-contained
"thread" building block, instead relying on precise setup in the usage
context -- however, not willing to yield yet, since that would be exactly
what I wanted to avoid: having technicalities of thread start, argument
handover and failure detection intermingled with the business code.
This commit is contained in:
Fischlurch 2023-10-08 17:26:36 +02:00
parent 08c3e76f14
commit fd0370bd11
3 changed files with 296 additions and 2 deletions

View file

@ -107,7 +107,7 @@
#include "lib/error.hpp"
#include "lib/nocopy.hpp"
#include "include/logging.h"
#include "lib/meta/function.hpp"
//#include "lib/builder-qualifier-support.hpp"//////////////////////////TODO
#include "lib/format-util.hpp"
#include "lib/result.hpp"
@ -135,6 +135,20 @@ namespace lib {
using std::is_same;
using std::__or_;
////////////////////////////////////////////////////////////////////////////////////////////////////OOO extract -> lib/meta
/**
* Metaprogramming helper to mark some arbitrary base type by subclassing.
* In most respects the _specially marked type_ behaves like the base; this
* can be used to mark some element at compile time, e.g. to direct it into
* a specialisation or let it pick some special overload.
*/
template<class BAS, size_t m=0>
struct Marked
: BAS
{
using BAS::BAS;
};
////////////////////////////////////////////////////////////////////////////////////////////////////OOO extract(End)
/** @internal wraps the C++ thread handle
* and provides some implementation details,
* which are then combined by the _policy template_
@ -261,8 +275,10 @@ namespace lib {
template<template<class,class> class POL, typename RES =void>
class ThreadLifecycle
: protected POL<ThreadWrapper, RES>
// , public lib::BuilderQualifierSupport<ThreadLifecycle<POL,RES>>
{
using Policy = POL<ThreadWrapper,RES>;
// using Qualifier = typename lib::BuilderQualifierSupport<ThreadLifecycle<POL,RES>>::Qualifier;
template<typename...ARGS>
void
@ -323,6 +339,44 @@ namespace lib {
,static_cast<SUB*> (this)
,forward<ARGS> (args)... }
{ }
struct ConfigBuilder
: util::MoveOnly
{
using Launcher = std::function<void(ThreadLifecycle&)>;
Launcher launch;
template<class FUN, typename...ARGS>
ConfigBuilder (FUN&& threadFunction, ARGS&& ...args)
: launch{[=]
(ThreadLifecycle& wrapper)
{
wrapper.threadImpl_
= std::thread{&ThreadLifecycle::invokeThreadFunction<FUN, decay_t<ARGS>...>
, &wrapper
, std::move(threadFunction)
, std::move(args)... };
}}
{ }
ConfigBuilder&&
threadID (string const& id)
{
launch = [=, chain=std::move(launch)]
(ThreadLifecycle& wrapper)
{
util::unConst(wrapper.threadID_) = id;
chain (wrapper);
};
return move(*this);
}
};
ThreadLifecycle (ConfigBuilder launcher)
: Policy{}
{
launcher.launch (*this);
}
};
}//(End)base implementation.

View file

@ -90,6 +90,11 @@ namespace test{
double offset = Dur{threadStart - afterCtor}.count();
SHOW_EXPR(offset)
CHECK (offset > 0);
Thread murks{Thread::ConfigBuilder([&]{
cout << "Hello inner world "<<rand()%47<<endl;
})
.threadID("haha")};
UNIMPLEMENTED ("demonstrate state change");
}

View file

@ -65484,7 +65484,7 @@
</node>
<node CREATED="1696640180387" ID="ID_1878688951" MODIFIED="1696640198386" TEXT="die Wrapper auf das anfangs definierte Minimum beschr&#xe4;nken">
<node CREATED="1696640214151" ID="ID_548509988" MODIFIED="1696640256973" TEXT="typischerweise auf Subsystem-Ebene und dort eine member-Var"/>
<node CREATED="1696640278102" ID="ID_362520772" MODIFIED="1696640302706" TEXT="Thread (Standardfall) so &#xe4;ndern, da&#xdf; es im dtor intern ein detach() macht"/>
<node CREATED="1696640278102" ID="ID_362520772" MODIFIED="1696640302706" TEXT="Thread (Standardfall) so &#xe4;ndern, da&#xdf; er im dtor intern ein detach() macht"/>
<node CREATED="1696640304051" ID="ID_838020700" MODIFIED="1696640339522" TEXT="daf&#xfc;r f&#xe4;llt detach() auf dem API weg und der SteamDispatcher bleibt wie er war"/>
</node>
<node CREATED="1696640573023" ID="ID_1848128254" MODIFIED="1696640645673" TEXT="Komplexit&#xe4;t akzeptieren und das Baukasten-System erweitern">
@ -65606,6 +65606,190 @@
</node>
</node>
<node CREATED="1696538580339" ID="ID_741763330" MODIFIED="1696538583740" TEXT="Implementierung">
<node CREATED="1696687299435" ID="ID_1271362386" MODIFIED="1696687306334" TEXT="Konfiguration erm&#xf6;glichen">
<node COLOR="#5b280f" CREATED="1696687326411" ID="ID_682366843" MODIFIED="1696773642410" TEXT="BuilderQualfierSupport nutzbar machen">
<icon BUILTIN="button_cancel"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696687354848" ID="ID_1619359990" MODIFIED="1696687358528" TEXT="Einsatz kl&#xe4;ren">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1696687359967" ID="ID_1324063173" MODIFIED="1696687373111" TEXT="mix-in wo?">
<icon BUILTIN="help"/>
<node CREATED="1696687398879" ID="ID_477151920" MODIFIED="1696687401765" TEXT="Regeln">
<node CREATED="1696687405817" ID="ID_1328952315" MODIFIED="1696687444511" TEXT="parameter TAR &#x2261; auf diesem Typ arbeiten die Qualifier"/>
<node CREATED="1696687576066" ID="ID_590991660" MODIFIED="1696688207005" TEXT="mix-in &#x27f9; ab diesem Scope ist der Typ Qualifier eingef&#xfc;hrt"/>
<node CREATED="1696687670085" ID="ID_1105883283" MODIFIED="1696688213833" TEXT="Argument-Builder als friends deklariert: Zugriff auf Interna"/>
</node>
<node CREATED="1696690647960" ID="ID_1742846503" MODIFIED="1696690658740" TEXT="deute ich so: es mu&#xdf; kein Mix-in sein"/>
<node CREATED="1696690659376" ID="ID_1064920188" MODIFIED="1696690678293" TEXT="viel wichtiger ist, wo die Argument-Builder als frieds stehen"/>
</node>
<node CREATED="1696690683733" ID="ID_805253305" MODIFIED="1696690770426" TEXT="TAR(Ziel-Typ) : ThreadLifecylce&lt;POL,RES&gt;">
<node CREATED="1696690772137" ID="ID_221934621" MODIFIED="1696690779324" TEXT="das bedeutet: alle Friends sind getemplated"/>
<node CREATED="1696690796286" ID="ID_548905336" MODIFIED="1696690806521" TEXT="sollte kein Problem darstellen">
<node CREATED="1696690810981" ID="ID_1972833988" MODIFIED="1696690824006" TEXT="zur Definition mu&#xdf; man POL nicht explizieren"/>
<node CREATED="1696690824506" ID="ID_105598857" MODIFIED="1696690856753" TEXT="und bei der Anwendung wird es per ADL gebunden"/>
</node>
<node CREATED="1696690871300" ID="ID_1528488763" MODIFIED="1696690893245" TEXT="die Argument-Builder sitzen dann auch dort, und wirken effektiv auf diese Konstruktoren"/>
<node CREATED="1696690894145" ID="ID_1214632249" MODIFIED="1696690928341" TEXT="es gibt (Plan.A) einen separaten, dedizierten Konstruktor ebenda"/>
</node>
</node>
<node COLOR="#fe0548" CREATED="1696691310924" ID="ID_252708158" MODIFIED="1696773419438" TEXT="Qualifier-Konstruktor">
<icon BUILTIN="closed"/>
<node CREATED="1696773422943" ID="ID_155610622" MODIFIED="1696773469213" TEXT="es gelingt nicht, die Builder-Funktionen sichtbar zu machen">
<icon BUILTIN="stop-sign"/>
</node>
<node CREATED="1696773470136" ID="ID_252509370" MODIFIED="1696773483525" TEXT="das ganze Konzept h&#xe4;ngt daran, da&#xdf; man unqualifizierte Terme verwendet"/>
<node CREATED="1696773486776" ID="ID_1067885474" MODIFIED="1696773504616" TEXT="diese m&#xfc;ssen aber &#xbb;indirekt&#xab; verdrahtet sein">
<node CREATED="1696773505628" ID="ID_1352395228" MODIFIED="1696773511054" TEXT="n&#xe4;mlich &#xfc;ber den R&#xfc;ckgabewert"/>
<node CREATED="1696773511517" ID="ID_666982787" MODIFIED="1696773517550" TEXT="dieser ist ein Funktor"/>
<node CREATED="1696773518114" ID="ID_1614803911" MODIFIED="1696773532948" TEXT="und arbeitet als Friend auf der zu konfiguierenden Klasse"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1696773535645" ID="ID_1992973527" MODIFIED="1696773553635" TEXT="das geht bei einfachen Typen, nicht aber bei Templates">
<icon BUILTIN="stop-sign"/>
<node CREATED="1696773558085" ID="ID_181042282" MODIFIED="1696773573941" TEXT="entweder es gelingt &#xfc;berhaupt nicht, die Friend-Deklarationen zu erzeugen"/>
<node CREATED="1696773574594" ID="ID_1440508280" MODIFIED="1696773603811" TEXT="oder sie generieren Funktionen, die im Namespace kollidieren"/>
<node CREATED="1696773604543" ID="ID_1045148333" MODIFIED="1696773618273" TEXT="oder die generierten Funktionen werden nicht ohne Qualifikation gefunden"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696773620748" ID="ID_1084392128" MODIFIED="1696773634824" TEXT="damit bricht das gesamte Konzept zusammen">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990070" CREATED="1696773651080" ID="ID_1779067664" MODIFIED="1696773681597" TEXT="(Verzweiflung ... die Uhr tickt)">
<font ITALIC="true" NAME="SansSerif" SIZE="11"/>
<icon BUILTIN="smily_bad"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1696773689915" ID="ID_505123094" MODIFIED="1696778498186" TEXT="dann bleibt wirklich nur noch ein Builder">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1696773711584" ID="ID_1136655892" MODIFIED="1696773718472" TEXT="Alternativen?">
<icon BUILTIN="help"/>
<node CREATED="1696773722487" ID="ID_1069796427" MODIFIED="1696773786376">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
es <b>mu&#223;</b>&#160;ein Konstruktor-Aufruf sein
</p>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
zwar k&#246;nnte man nun generell an eine Factory denken, aber diese verlagert die gesamten Gefahren mit dem Instance-Management auf den usage-Kontext, und untergr&#228;bt damit den Zweck des Unterfangens...
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1696773788022" ID="ID_103067174" MODIFIED="1696773810341">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
er <b>soll</b>&#160;einfach und sprechend sein
</p>
</body>
</html></richcontent>
<icon BUILTIN="yes"/>
</node>
<node CREATED="1696773813191" ID="ID_921625697" MODIFIED="1696773886262">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
der Einstieg mu&#223; <b>zuverl&#228;ssig</b>&#160;im Typ verankert sein
</p>
</body>
</html></richcontent>
</node>
<node COLOR="#435e98" CREATED="1696773922124" ID="ID_310300656" MODIFIED="1696774335094" TEXT="&#x27f9; bleibt nur der Einstieg &#xfc;ber eine statische Methode im Zieltyp"/>
<node CREATED="1696773947217" ID="ID_897608956" MODIFIED="1696774304294">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
also....
</p>
<p>
</p>
<p>
<font color="#1b0d7b" face="Monospaced" size="2">unique_ptr&lt;ThreadHookable&gt; thread; </font>
</p>
<p>
<font color="#1b0d7b" face="Monospaced" size="2">thread.reset( </font>
</p>
<p>
<font color="#1b0d7b" face="Monospaced" size="2">&#160;&#160;&#160;&#160;new&#160;ThreadHookable{ </font>
</p>
<p>
<font color="#1b0d7b" face="Monospaced" size="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;ThreadHookable::launch(myFunctor, arg) </font>
</p>
<p>
<font color="#1b0d7b" face="Monospaced" size="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;.atStart(initHook) </font>
</p>
<p>
<font color="#1b0d7b" face="Monospaced" size="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;.atEnd(terminationHook)}); </font>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1696774321215" ID="ID_1696275940" MODIFIED="1696774330486" TEXT="Suche nach sonstigen Alternativen vertagt">
<icon BUILTIN="hourglass"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1696774572285" ID="ID_882374829" MODIFIED="1696778493850" TEXT="Zwibelschalen-Design">
<icon BUILTIN="pencil"/>
<node CREATED="1696774580118" ID="ID_1750789171" MODIFIED="1696774597403" TEXT="der Builder ist ein tempor&#xe4;rer Typ (f&#xfc;r jeden aufruf spezifisch)"/>
<node CREATED="1696774626822" ID="ID_1811542479" MODIFIED="1696774694500">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
er bietet als internes API eine Funktion <font color="#5c403a" face="Monospaced"><b>configure(this)</b></font>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1696774705297" ID="ID_1802183110" MODIFIED="1696774767328" TEXT="jede zus&#xe4;tzliche chained-Builder-Methode legt dar&#xfc;ber eine weitere Zwiebelschale"/>
<node COLOR="#338800" CREATED="1696778510767" ID="ID_1939881196" MODIFIED="1696778521972" TEXT="Konzept-Studie">
<icon BUILTIN="button_ok"/>
<node CREATED="1696778523133" ID="ID_1413219977" MODIFIED="1696778539719" TEXT="verkettete &#x3bb; verwenden"/>
<node CREATED="1696778542855" ID="ID_1727243560" MODIFIED="1696778566277" TEXT="noch gewisse Probleme mit dem decay_t und dem kopieren von Argumenten">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1696778568283" ID="ID_999434014" MODIFIED="1696778580090" TEXT="ich mu&#xdf; jetzt Funktor und Argumente in das &#x3bb; kopieren"/>
<node CREATED="1696778580835" ID="ID_1429363688" MODIFIED="1696778795182" TEXT="bekanntes Problem ohne einfache L&#xf6;sung">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
da bin ich schon x-mal dar&#252;ber gestolpert: man kann per Reference oder per Value initialisieren; was nicht funktioniert ist eine move-Initialisierung, d.h. jeder move-only Argument-Typ macht Probleme. Einziger Ausweg war f&#252;r mich bisher, die captures explizit zu benennen und per std::forward-assign zu initialisieren
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1696778678441" ID="ID_381933482" MODIFIED="1696778697722" TEXT="...und zwar weil es ein &#x3bb;-capture by value sein mu&#xdf;"/>
</node>
</node>
</node>
</node>
</node>
<node CREATED="1696538593318" ID="ID_1072499488" MODIFIED="1696538606616" TEXT="neue Policies...">
<node CREATED="1696538616428" ID="ID_203239471" MODIFIED="1696538652470" TEXT="spezialisieren beide auf PolicyLaunchOnly">
<icon BUILTIN="idea"/>
@ -65617,6 +65801,57 @@
<node CREATED="1696538607372" ID="ID_479618351" MODIFIED="1696538611095" TEXT="f&#xfc;r Variante-1"/>
<node CREATED="1696538612261" ID="ID_661367597" MODIFIED="1696538614839" TEXT="f&#xfc;r Variante-2"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696690988844" ID="ID_480585061" MODIFIED="1696690995950" TEXT="das Race-Problem addressieren">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1696690998156" ID="ID_394310225" MODIFIED="1696691010645" TEXT="der Thread wird erst aus dem Konstruktor-Rumpf gestartet"/>
<node CREATED="1696691012041" ID="ID_1592624785" MODIFIED="1696691021403" TEXT="daf&#xfc;r gibt es eine neue Policy-Funktion"/>
<node CREATED="1696691275142" ID="ID_178562434" MODIFIED="1696691300398" TEXT="aufgedoppelt f&#xfc;r den Qualifier-Konstruktor">
<node CREATED="1696691320304" ID="ID_1114482124" MODIFIED="1696691337153" TEXT="da dieser unbedingt vor dem Launch noch die Qualifier aktivieren mu&#xdf;"/>
<node CREATED="1696691363258" ID="ID_1604122768" MODIFIED="1696691380443" TEXT="es sei den... man macht den Qualifier-Konstruktor zum Basisfall"/>
</node>
<node CREATED="1696691391111" ID="ID_939791093" MODIFIED="1696691405089" TEXT="Problem: Funktor-Argumentliste">
<node CREATED="1696691415615" ID="ID_167830298" MODIFIED="1696691425773" TEXT="im einfachen Fall problemlos (perfect forwarding)"/>
<node CREATED="1696691426433" ID="ID_921129676" MODIFIED="1696691497844" TEXT="aber mit Qualifier? pa&#xdf;t nicht so recht">
<node CREATED="1696691501159" ID="ID_1948526889" MODIFIED="1696691527488" TEXT="diese Argumentliste wirkt nicht wie ein Setter"/>
<node CREATED="1696691528052" ID="ID_867534321" MODIFIED="1696691543456" TEXT="sondern sie wird an einen Konstruktor (std::thread) weitergereicht"/>
<node CREATED="1696691549747" ID="ID_869387928" MODIFIED="1696691563483" TEXT="die Qualifier arbeiten aber auf einem bereits vorinitialisierten *this"/>
<node CREATED="1696691818733" ID="ID_1953646556" MODIFIED="1696691823856" TEXT="L&#xf6;sungsm&#xf6;glichkeiten">
<node CREATED="1696691830883" ID="ID_863734733" MODIFIED="1696691850173" TEXT="man mu&#xdf; eben doch irgendwo in *this einen Funktor vorbereiten"/>
<node CREATED="1696691855112" ID="ID_637690" MODIFIED="1696691890092" TEXT="die Thread-Funktion nicht per Qualifier &#xfc;bergeben">
<node CREATED="1696691894483" ID="ID_1033784353" MODIFIED="1696691903061" TEXT="sondern als positionale Parameter"/>
<node CREATED="1696691903618" ID="ID_1672986588" MODIFIED="1696691917300" TEXT="bedeutet: brauche Filter &#xfc;ber Variadische Argumente"/>
<node CREATED="1696692386490" ID="ID_1508032921" MODIFIED="1696692408223" TEXT="Qualifier ausf&#xfc;hren und alle sonstigen Argumente &#x27f6; Tupel">
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1696691920306" ID="ID_528497572" MODIFIED="1696692215988" TEXT="ein Qualifier launch(fun, args...) ruft direkt das POL::launchThread auf">
<node CREATED="1696692108630" ID="ID_191058307" MODIFIED="1696692116545" TEXT="in dem Moment wird der Thread gestaret"/>
<node CREATED="1696692117109" ID="ID_540268205" MODIFIED="1696692134079" TEXT="das m&#xfc;&#xdf;te dann aber der letzte Qualifier sein"/>
<node CREATED="1696692179757" ID="ID_801136896" MODIFIED="1696692187135" TEXT="gef&#xe4;hrlich und verwirrend">
<icon BUILTIN="stop-sign"/>
</node>
</node>
<node CREATED="1696692189756" ID="ID_1013652330" MODIFIED="1696692249462" TEXT="diesen speziellen Qualifier irgendwie filtern">
<node CREATED="1696692250836" ID="ID_495269824" MODIFIED="1696692276082" TEXT="nicht einfach... es ist kein Typ"/>
<node CREATED="1696692310201" ID="ID_485258287" MODIFIED="1696692318311" TEXT="sondern ein Term vom Typ Qualifier">
<node CREATED="1696692321929" ID="ID_1108650481" MODIFIED="1696692339883" TEXT="d.h, lediglich eine opaque std::function"/>
<node CREATED="1696692360530" ID="ID_604231909" MODIFIED="1696692369921" TEXT="auch einen Subtyp w&#xfc;rde man hier nicht mehr sehen"/>
</node>
</node>
<node CREATED="1696711803811" ID="ID_830334623" MODIFIED="1696711817207" TEXT="viel einfacher: ihn explizit am Anfang der Argumentliste erwarten"/>
<node CREATED="1696774366414" ID="ID_768133943" MODIFIED="1696774412701" TEXT="durch Builder-Syntax und tempor&#xe4;res Objekt explizit l&#xf6;sen">
<linktarget COLOR="#ab3573" DESTINATION="ID_768133943" ENDARROW="Default" ENDINCLINATION="-135;7;" ID="Arrow_ID_222249914" SOURCE="ID_423350033" STARTARROW="None" STARTINCLINATION="186;8;"/>
<node CREATED="1696774433105" ID="ID_1904794214" MODIFIED="1696774466735" TEXT="der Builder wird direkt mit dem eigentlichen Funktor er&#xf6;ffnet"/>
<node CREATED="1696774467368" ID="ID_138567453" MODIFIED="1696774473433" TEXT="alle weiteren Argumente sind optional"/>
</node>
</node>
</node>
</node>
<node COLOR="#5b280f" CREATED="1696773328397" ID="ID_423350033" MODIFIED="1696774419956" TEXT="L&#xf6;sung mit Qualifier-ctor scheitert an (nicht vorhandenem) ADL">
<arrowlink COLOR="#ab3573" DESTINATION="ID_768133943" ENDARROW="Default" ENDINCLINATION="-135;7;" ID="Arrow_ID_222249914" STARTARROW="None" STARTINCLINATION="186;8;"/>
<icon BUILTIN="closed"/>
</node>
</node>
</node>
<node CREATED="1696538743210" ID="ID_1370366397" MODIFIED="1696538750437" TEXT="Tests erg&#xe4;nzen">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696538756712" ID="ID_1688404846" MODIFIED="1696541608160" TEXT="ThreadWrapperAutonomous_test">