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:
parent
fd0370bd11
commit
faa0d3e211
3 changed files with 79 additions and 39 deletions
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65329,8 +65329,7 @@
|
|||
...sonst wä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 @@
|
|||
⟹ <i>Initialisierung</i> von Policy-Bausteinen <i>ist nicht mö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> könnte die Thread-Funktion bereits mit der Initialisierung des lib::Result beginnen, wä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äß der OS-Scheduler immer <i>eine gewisse</i> Latenz hat, bis ein Thread tatsächlich ausfü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 ⟶ 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">                           .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ärer Typ (fü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ätzliche chained-Builder-Methode legt darü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 λ 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ß jetzt Funktor und Argumente in das λ kopieren"/>
|
||||
<node CREATED="1696778580835" ID="ID_1429363688" MODIFIED="1696778795182" TEXT="bekanntes Problem ohne einfache Lösung">
|
||||
|
|
@ -65781,11 +65774,35 @@
|
|||
da bin ich schon x-mal darü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ü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 λ-capture by value sein muß"/>
|
||||
</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 λ 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 ⟹ die Hilfsfunktion ist unvermeidlich">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
wenn halt Argument-Packs einfach als Typ repräsentierbar wären — aber dem ist nicht so; man muß 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 üblich: std::index_sequence_for<TYPES...>"/>
|
||||
</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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue