From fd0370bd11235b2b5c3c5bebc90e50d89c4b17e9 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 8 Oct 2023 17:26:36 +0200 Subject: [PATCH] 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. --- src/lib/thread.hpp | 56 ++++- .../library/thread-wrapper-lifecycle-test.cpp | 5 + wiki/thinkPad.ichthyo.mm | 237 +++++++++++++++++- 3 files changed, 296 insertions(+), 2 deletions(-) diff --git a/src/lib/thread.hpp b/src/lib/thread.hpp index fa32efe83..068eedbcd 100644 --- a/src/lib/thread.hpp +++ b/src/lib/thread.hpp @@ -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 + 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 class POL, typename RES =void> class ThreadLifecycle : protected POL +// , public lib::BuilderQualifierSupport> { using Policy = POL; +// using Qualifier = typename lib::BuilderQualifierSupport>::Qualifier; template void @@ -323,6 +339,44 @@ namespace lib { ,static_cast (this) ,forward (args)... } { } + + struct ConfigBuilder + : util::MoveOnly + { + using Launcher = std::function; + Launcher launch; + + template + ConfigBuilder (FUN&& threadFunction, ARGS&& ...args) + : launch{[=] + (ThreadLifecycle& wrapper) + { + wrapper.threadImpl_ + = std::thread{&ThreadLifecycle::invokeThreadFunction...> + , &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. diff --git a/tests/library/thread-wrapper-lifecycle-test.cpp b/tests/library/thread-wrapper-lifecycle-test.cpp index 56230fa45..79c2f036a 100644 --- a/tests/library/thread-wrapper-lifecycle-test.cpp +++ b/tests/library/thread-wrapper-lifecycle-test.cpp @@ -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 "< - + @@ -65606,6 +65606,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ es muß ein Konstruktor-Aufruf sein +

+ +
+ + + + + +

+ zwar könnte man nun generell an eine Factory denken, aber diese verlagert die gesamten Gefahren mit dem Instance-Management auf den usage-Kontext, und untergräbt damit den Zweck des Unterfangens... +

+ +
+
+ + + + + + +

+ er soll einfach und sprechend sein +

+ +
+ +
+ + + + + + +

+ der Einstieg muß zuverlässig im Typ verankert sein +

+ +
+
+ + + + + + + +

+ also.... +

+

+ +

+

+ unique_ptr<ThreadHookable> thread; +

+

+ thread.reset( +

+

+     new ThreadHookable{ +

+

+             ThreadHookable::launch(myFunctor, arg) +

+

+                            .atStart(initHook) +

+

+                            .atEnd(terminationHook)}); +

+ + +
+ +
+ + + +
+ + + + + + + + + +

+ er bietet als internes API eine Funktion configure(this) +

+ + +
+
+ + + + + + + + + + + + + +

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

+ + +
+
+ + +
+
+
+
@@ -65617,6 +65801,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +