Library: solved embedding arbitrary argument sequences

Concept study of the intended solution successful.

Can now transparently embed any conceivable functor
and an arbitrary argument sequence into a launcher-λ
Materialising into a std::tuple<decay_t<TYPES...>> did the trick.
This commit is contained in:
Fischlurch 2023-10-09 02:57:03 +02:00
parent fd0370bd11
commit faa0d3e211
3 changed files with 79 additions and 39 deletions

View file

@ -107,13 +107,13 @@
#include "lib/error.hpp"
#include "lib/nocopy.hpp"
#include "include/logging.h"
//#include "lib/builder-qualifier-support.hpp"//////////////////////////TODO
#include "lib/format-util.hpp"
#include "lib/result.hpp"
#include <utility>
#include <thread>
#include <string>
#include <utility>
#include <tuple>
namespace util {
@ -122,6 +122,7 @@ namespace util {
namespace lib {
using std::string;
using std::tuple;
@ -129,9 +130,12 @@ namespace lib {
using lib::meta::typeSymbol;
using std::forward;
using std::move;
using std::decay_t;
using std::invoke_result_t;
using std::is_constructible;
using std::index_sequence_for;
using std::index_sequence;
using std::is_same;
using std::__or_;
@ -275,10 +279,8 @@ 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
@ -339,27 +341,46 @@ namespace lib {
,static_cast<SUB*> (this)
,forward<ARGS> (args)... }
{ }
struct ConfigBuilder
template<typename...INVO, size_t...idx>
static auto
buildLauncher_impl (tuple<INVO...>&& argCopy, index_sequence<idx...>)
{
return [invocation = move(argCopy)]
(ThreadLifecycle& wrapper)
{
ASSERT (not wrapper.isLive());
wrapper.threadImpl_
= std::thread{&ThreadLifecycle::invokeThreadFunction<INVO...>
, &wrapper
, move(std::get<idx> (invocation))... };
};
}
template<class...INVO>
static auto
buildLauncher (INVO&& ...args)
{
// materialise functor and arguments as copy, to be handed over into the new thread
return buildLauncher_impl (tuple<decay_t<INVO>...>{forward<INVO> (args)...}
,index_sequence_for<INVO...>{});
}
struct Launch
: 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)... };
}}
Launch (FUN&& threadFunction, ARGS&& ...args)
: launch{buildLauncher (forward<FUN>(threadFunction), forward<ARGS>(args)...)}
{ }
ConfigBuilder&&
Launch&&
threadID (string const& id)
{
launch = [=, chain=std::move(launch)]
@ -372,9 +393,9 @@ namespace lib {
}
};
ThreadLifecycle (ConfigBuilder launcher)
ThreadLifecycle (Launch launcher)
: Policy{}
{
{
launcher.launch (*this);
}
};

View file

@ -91,9 +91,11 @@ namespace test{
SHOW_EXPR(offset)
CHECK (offset > 0);
Thread murks{Thread::ConfigBuilder([&]{
cout << "Hello inner world "<<rand()%47<<endl;
})
Thread murks{Thread::Launch([&](uint scope)
{
cout << "Hello nested world "<<rand()%scope <<endl;
}
, 47)
.threadID("haha")};
UNIMPLEMENTED ("demonstrate state change");
}

View file

@ -65329,8 +65329,7 @@
...sonst w&#228;re das ganze Unterfangen theoretischer Natur; nur dadurch wird es interessant, Storage zu verwalten und einen Zugang freizuschalten
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1696621067492" ID="ID_1848245258" MODIFIED="1696621085856" TEXT="der Session-Thread braucht einen smart-ptr als Front-End">
<node CREATED="1696621086981" ID="ID_427538750" MODIFIED="1696621153920" TEXT="1. es ist ein PImpl (mit eigenem API)"/>
@ -65368,8 +65367,7 @@
&#10233;&#160;<i>Initialisierung</i>&#160;von Policy-Bausteinen <i>ist nicht m&#246;glich</i>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<arrowlink COLOR="#fe225e" DESTINATION="ID_1852065850" ENDARROW="Default" ENDINCLINATION="147;-294;" ID="Arrow_ID_1803073395" STARTARROW="None" STARTINCLINATION="-332;18;"/>
<node CREATED="1696624710262" ID="ID_798050443" MODIFIED="1696624792744" TEXT="Konsequenz: ThreadJoinable ist (latent) racy">
<richcontent TYPE="NOTE"><html>
@ -65384,8 +65382,7 @@
<i>streng genommen</i>&#160;k&#246;nnte die Thread-Funktion bereits mit der Initialisierung des lib::Result beginnen, w&#228;hrend ihr dann die default-Initialisierung dazwischenfunkt
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1696624920612" ID="ID_1218441049" MODIFIED="1696624940325" TEXT="...und jede Erweiterung, die Daten in der Policy hat, ebenfalls"/>
</node>
@ -65409,8 +65406,7 @@
da erfahrungsgem&#228;&#223; der OS-Scheduler immer <i>eine gewisse</i>&#160;Latenz hat, bis ein Thread tats&#228;chlich ausf&#252;hrbar wird
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<node COLOR="#338800" CREATED="1696628723995" ID="ID_1617045707" MODIFIED="1696639807086" TEXT="nochmal Beobachtungen machen">
<icon BUILTIN="button_ok"/>
<node CREATED="1696639643860" ID="ID_82825911" MODIFIED="1696639649431" TEXT="std::system_clock"/>
@ -65455,8 +65451,7 @@
und per move-assign auf das Handle schiebt.
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="idea"/>
<node CREATED="1696628821820" ID="ID_1115877978" MODIFIED="1696628844773" TEXT="std::thread is default constructible &#x27f6; inaktiv"/>
<node CREATED="1696628845625" ID="ID_1290073525" MODIFIED="1696628855357" TEXT="und es gibt einen move-assignment-Operator"/>
@ -65740,15 +65735,14 @@
<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>
</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">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1696774572285" ID="ID_882374829" MODIFIED="1696799236893" TEXT="Zwiebelschalen-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">
@ -65761,14 +65755,13 @@
er bietet als internes API eine Funktion <font color="#5c403a" face="Monospaced"><b>configure(this)</b></font>
</p>
</body>
</html>
</richcontent>
</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">
<node CREATED="1696778542855" ID="ID_1727243560" MODIFIED="1696799211641" 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">
@ -65781,11 +65774,35 @@
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>
</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 CREATED="1696812275033" ID="ID_964321328" MODIFIED="1696812333238" TEXT="materialisiere Funktor + Argumente in ein Tupel">
<icon BUILTIN="idea"/>
<node CREATED="1696812336727" ID="ID_798176244" MODIFIED="1696812344930" TEXT="dabei kann man decay_t bilden"/>
<node CREATED="1696812345990" ID="ID_1021291890" MODIFIED="1696812369394" TEXT="und dieses Tupel dann in das &#x3bb; verschieben"/>
</node>
<node CREATED="1696812299764" ID="ID_166961627" MODIFIED="1696812330308" TEXT="und entlade das mit einer Hilfsfunktion in den std::thread-Konstruktor">
<node CREATED="1696812379266" ID="ID_870864473" MODIFIED="1696812462503" TEXT="ja... varargs &#x27f9; die Hilfsfunktion ist unvermeidlich">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
wenn halt Argument-Packs einfach als Typ repr&#228;sentierbar w&#228;ren &#8212; aber dem ist nicht so; man mu&#223; gegen ein getemplatetes Argument matchen, um aus einem Argument-Pack einen anderen Argument-Pack zu konstruieren
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1696812473885" ID="ID_1487641552" MODIFIED="1696812488838" TEXT="wie &#xfc;blich: std::index_sequence_for&lt;TYPES...&gt;"/>
</node>
<node CREATED="1696812766502" ID="ID_124892301" MODIFIED="1696812776928" TEXT="Thread-start funktioniert, auch mit Parameter"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696812791066" ID="ID_1789709297" MODIFIED="1696812798545" TEXT="Code sinnvoll anordnen">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>