Library: rearrange launch into the base policy
this is a mere rearrangement of code (+lots of comments), but helps to structure the overall construction better. ThreadWrapper::launchThread() now does the actual work to build the active std::thread object and assign it to the thread handle, while buildLauncher is defined in the context of the constructors and deals with wiring the functors and decaying/copying of arguments.
This commit is contained in:
parent
2d7137e776
commit
8518cf1fa0
2 changed files with 67 additions and 16 deletions
|
|
@ -129,6 +129,7 @@ namespace lib {
|
|||
namespace thread {// Thread-wrapper base implementation...
|
||||
|
||||
using lib::meta::typeSymbol;
|
||||
using std::function;
|
||||
using std::forward;
|
||||
using std::move;
|
||||
using std::decay_t;
|
||||
|
|
@ -178,6 +179,29 @@ namespace lib {
|
|||
, threadImpl_{forward<ARGS> (args)... }
|
||||
{ }
|
||||
|
||||
/** @internal actually launch the new thread.
|
||||
* Deliberately the #threadImpl_ is created empty, to allow for complete
|
||||
* initialisation of all the combined policy classes stacked on top
|
||||
* @warning Start of the new thread _syncs-with_ the return from std::thread ctor.
|
||||
* Thus -- in theory -- initialising members of derived classes after constructing
|
||||
* a non-empty std::thread object would be *undefined behaviour*. In practice however,
|
||||
* this is more of a „theoretical“ problem, since the OS scheduler has a considerable
|
||||
* latency, so that the code within the new thread typically starts executing with an
|
||||
* delay of _at least 100µs_
|
||||
* @remark non the less, the thread-wrapper framework circumvents this possible undefined behaviour,
|
||||
* by first creating the threadImpl_ empty, and only later move-assigning the std::thread.
|
||||
* @param invocation a tuple holding some invokable and possible arguments, together forming the
|
||||
* threadFunction to be executed in the new thread.
|
||||
*/
|
||||
template<class...INVO>
|
||||
void
|
||||
launchThread (tuple<INVO...>&& invocation)
|
||||
{
|
||||
ASSERT (not isLive(), "Thread already running");
|
||||
threadImpl_ = make_from_tuple<std::thread> (invocation);
|
||||
};
|
||||
|
||||
|
||||
/** detect if the currently executing code runs within this thread */
|
||||
bool invokedWithinThread() const;
|
||||
|
||||
|
|
@ -344,29 +368,44 @@ namespace lib {
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Build a λ actually to launch the given thread operation later,
|
||||
* after the thread-wrapper-object is fully initialised.
|
||||
* The member function #invokeThreadFunction will be run as top-level
|
||||
* within the new thread, possibly handling errors, but delegating to
|
||||
* the user-provided actual thread-operation
|
||||
* @param args a invokable + further arguments
|
||||
* @note the invokable and the arguments will be materialised/copied
|
||||
* thereby decaying the given type; this is necessary, because
|
||||
* these arguments must be copied into the new thread. This will
|
||||
* fail to compile, if the given invokable can not be invoked
|
||||
* with these copied (and decayed) arguments.
|
||||
*/
|
||||
template<class...INVO>
|
||||
static auto
|
||||
buildLauncher (INVO&& ...args)
|
||||
{
|
||||
// materialise functor and arguments as copy, to be handed over into the new thread
|
||||
tuple<decay_t<INVO>...> argCopy{forward<INVO> (args)...};
|
||||
return [invocation = move(argCopy)]
|
||||
return [invocation = move(argCopy)] //Note: functor+args bound by-value into the λ
|
||||
(ThreadLifecycle& wrapper)
|
||||
{
|
||||
auto threadArgs = tuple_cat (tuple{&ThreadLifecycle::invokeThreadFunction<INVO...>, &wrapper}
|
||||
,move (invocation));
|
||||
ASSERT (not wrapper.isLive());
|
||||
wrapper.threadImpl_
|
||||
= make_from_tuple<std::thread> (threadArgs);
|
||||
};
|
||||
{ //the thread-main function
|
||||
wrapper.launchThread (tuple_cat (tuple{&ThreadLifecycle::invokeThreadFunction<INVO...>
|
||||
, &wrapper} // passing the wrapper as instance-this
|
||||
,move (invocation))); //...invokeThreadFunction() in turn delegates
|
||||
}; // to the user-provided thread-operation
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configuration builder to define the operation to run in the thread,
|
||||
* and possibly configure further details, depending on the Policy used.
|
||||
* @remark the primary ThreadLifecycle-ctor accepts such a Launch-instance
|
||||
* and invokes the chain of λ-functions collected in the member #launch
|
||||
*/
|
||||
struct Launch
|
||||
: util::MoveOnly
|
||||
{
|
||||
using Launcher = std::function<void(ThreadLifecycle&)>;
|
||||
Launcher launch;
|
||||
function<void(ThreadLifecycle&)> launch;
|
||||
|
||||
template<class FUN, typename...ARGS>
|
||||
Launch (FUN&& threadFunction, ARGS&& ...args)
|
||||
|
|
|
|||
|
|
@ -65704,7 +65704,7 @@
|
|||
</html></richcontent>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1696773922124" ID="ID_310300656" MODIFIED="1696774335094" TEXT="⟹ bleibt nur der Einstieg über eine statische Methode im Zieltyp"/>
|
||||
<node CREATED="1696773947217" ID="ID_897608956" MODIFIED="1696774304294">
|
||||
<node CREATED="1696773947217" ID="ID_897608956" MODIFIED="1696817454466">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -65726,7 +65726,7 @@
|
|||
<font color="#1b0d7b" face="Monospaced" size="2">    new ThreadHookable{ </font>
|
||||
</p>
|
||||
<p>
|
||||
<font color="#1b0d7b" face="Monospaced" size="2">            ThreadHookable::launch(myFunctor, arg) </font>
|
||||
<font color="#1b0d7b" face="Monospaced" size="2">            ThreadHookable::Launch(myFunctor, arg) </font>
|
||||
</p>
|
||||
<p>
|
||||
<font color="#1b0d7b" face="Monospaced" size="2">                           .atStart(initHook) </font>
|
||||
|
|
@ -65735,7 +65735,8 @@
|
|||
<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">
|
||||
|
|
@ -65801,13 +65802,24 @@
|
|||
</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 BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1696812791066" ID="ID_1789709297" MODIFIED="1696817507333" TEXT="Code sinnvoll anordnen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1696813183208" ID="ID_100161158" MODIFIED="1696813227123" TEXT="jetzt noch die invokeThreadFunctor-Memberfunktion mit in das Tupel packen..."/>
|
||||
<node CREATED="1696813171800" ID="ID_155742882" MODIFIED="1696813229500" TEXT="Ha! std::make_from_tuple">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1696816614379" ID="ID_1380705903" MODIFIED="1696816646902" TEXT="das Starten und Zuweisen in eine Hilfsfunktion ⬊ in die ThreadWrapper-Basisklasse">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#6e4398" CREATED="1696817088763" ID="ID_1405496774" MODIFIED="1696817115630" TEXT="so langsam nimmt dieses Konstrukt eine Form an, mit der ich leben kann...">
|
||||
<icon BUILTIN="smiley-neutral"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696817478656" ID="ID_1607424036" MODIFIED="1696817494294" TEXT="Umbau der bestehenden Konstruktoren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1696817511875" ID="ID_5608930" MODIFIED="1696817549173" TEXT="zwar wird weiterhin der Konstruktor mit threadID + Funktor am meisten verwendet"/>
|
||||
<node CREATED="1696817550022" ID="ID_1116307132" MODIFIED="1696817567896" TEXT="...aber der neue Konstruktor mit Builder wird nun zum Basis-Fall"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue