Library: complete the Thread-joining policy

after all this groundwork, implementing the invocation,
capturing and hand-over of results is simple, and the
thread-wrapper classes became fairly understandable.
This commit is contained in:
Fischlurch 2023-09-28 01:09:07 +02:00
parent 620639b7ce
commit 2c18c39c18
7 changed files with 321 additions and 245 deletions

View file

@ -73,7 +73,7 @@ namespace lib {
inline auto
failsafeInvoke (std::exception_ptr& capturedFailure
,FUN&& callable
,ARGS&& ...args)
,ARGS&& ...args) noexcept
{
using Res = std::invoke_result_t<FUN,ARGS...>;
try {
@ -129,7 +129,7 @@ namespace lib {
/** invoke a _callable_ and mark success or failure */
template<class FUN, typename...ARGS, typename=lib::meta::enable_if<std::is_invocable<FUN,ARGS...>>>
Result (FUN&& callable, ARGS&& ...args)
Result (FUN&& callable, ARGS&& ...args) noexcept
: failure_{}
{
failsafeInvoke (failure_
@ -180,7 +180,7 @@ namespace lib {
/** invoke a _callable_ and capture result in one shot */
template<class FUN, typename...ARGS, typename=lib::meta::enable_if<std::is_invocable<FUN,ARGS...>>>
Result (FUN&& callable, ARGS&& ...args)
Result (FUN&& callable, ARGS&& ...args) noexcept
: Result<void>{true}
, value_{failsafeInvoke (failure_
,std::forward<FUN> (callable)
@ -222,11 +222,11 @@ namespace lib {
}
};
/** deduction guard: allow _perfect forwarding_ of a any result into the ctor call. */
/** deduction guide: allow _perfect forwarding_ of a any result into the ctor call. */
template<typename VAL, typename=lib::meta::disable_if<std::is_invocable<VAL>>>
Result (VAL&&) -> Result<VAL>;
/** deduction guard: find out about result value to capture from a generic callable. */
/** deduction guide: find out about result value to capture from a generic callable. */
template<typename FUN, typename...ARGS>
Result (FUN&&, ARGS&&...) -> Result<std::invoke_result_t<FUN,ARGS...>>;

View file

@ -48,6 +48,8 @@ namespace lib {
namespace thread{
namespace {
const auto SHUTDOWN_GRACE_PERIOD = 20ms;
string
lifecycleMsg (Literal phase, string threadID)
{
@ -95,7 +97,7 @@ namespace thread{
try {
auto start = steady_clock::now();
while (threadImpl_.joinable()
and steady_clock::now () - start < 20ms
and steady_clock::now () - start < SHUTDOWN_GRACE_PERIOD
)
std::this_thread::yield();
}

View file

@ -24,15 +24,16 @@
/** @file thread.hpp
** Convenience front-end to simplify and codify basic thread handling.
** While the implementation of threading and concurrency support is based on the C++
** standard library, using in-project wrappers as front-end allows to codify some preferences
** and provide simplifications for the prevalent use case. Notably, threads which must be
** _joined_ are qualified as special case, while the standard case will just `detach()`
** at thread end. The main-level of each thread catches exceptions, which are typically
** ignored to keep the application running. Moreover, similar convenience wrappers are
** provided to implement [N-fold synchronisation](\ref lib::SyncBarrier) and to organise
** global locking and waiting in accordance with the _Object Monitor_ pattern. Together,
** these aim at packaging concurrency facilities into self-contained RAII-style objects.
** While the implementation of threading and concurrency support is based on the
** C++ standard library, using in-project wrappers as front-end allows to codify some
** references and provide simplifications for the prevalent use case. Notably, threads
** which must be _joined_ are qualified as special case, while the standard case will
** just `detach()` at thread end. The main-level of each thread catches exceptions, which
** are typically ignored to keep the application running. Moreover, similar convenience
** wrappers are provided to implement [N-fold synchronisation](\ref lib::SyncBarrier)
** and to organise global [locking and waiting](\ref lib::Sync) in accordance with the
** _Object Monitor_ pattern. In concert, these allow to package concurrency facilities
** into self-contained RAII-style objects.
**
** # Usage
** Based on experience, there seem to be two fundamentally different usage patterns for
@ -43,19 +44,21 @@
**
** The »just launch it« scheme is considered the default and embodied into lib::Thread.
** Immediately launched on construction using the given _Invokable Functor_ and binding arguments,
** it is not meant to be managed further, beyond possibly detecting the live-ness state through
** `bool`-check. Exceptions propagating to top level within the new thread will be catched and
** ignored, terminating and discarding the thread. Note however, since especially derived
** such a thread is not meant to be managed further, beyond possibly detecting the live-ness state
** through `bool`-check. Exceptions propagating to top level within the new thread will be coughed
** and ignored, terminating and discarding the thread. Note however, since especially derived
** classes can be used to create a safe anchor and working space for the launched operations,
** it must be avoided to discard the Thread object while still operational; as a matter of
** it must be avoided to destroy the Thread object while still operational; as a matter of
** design, it should be assured the instance object outlives the enclosed chain of activity.
** As a convenience, the destructor blocks for a short timespan of 20ms; a thread running
** beyond that grace period will kill the whole application by `std::terminate`.
**
** For the exceptional case when a supervising thread need to await the termination of
** launched threads, a different front-end \ref lib::ThreadJoinable is provided, exposing
** the `join()` operation. Such threads *must* be joined however, and thus the destructor
** immediately terminates the application in case the thread is still running.
** the `join()` operation. This operation returns a [»Either« wrapper](\ref lib::Result),
** to transport the return value and possible exceptions from the thread function to the
** caller. Such threads *must* be joined however, and thus the destructor immediately
** terminates the application in case the thread is still running.
**
** ## Synchronisation
** The C++ standard provides that the end of the `std::thread` constructor _syncs-with_ the
@ -73,7 +76,7 @@
** in cases where a race could be critical, additional means must be implemented; a
** possible solution would be to use a [N-fold synchronisation barrier](\ref lib::SyncBarrier)
** explicitly, or otherwise to ensure there is sufficient delay in the starting thread function.
**
**
** @remarks Historical design evolution:
** - Lumiera offered simplified convenience wrappers long before a similar design
** became part of the C++14 standard. These featured the distinction in join-able or
@ -92,8 +95,8 @@
** and paved the way for switch-over to the threading support meanwhile part of the
** C++ standard library. Design and semantics were retained, while implemented
** using modern features, notably the new _Atomics_ synchronisation framework.
**
** [syncs-with definition] : https://en.cppreference.com/w/cpp/atomic/memory_order#Synchronizes_with
** @todo WIP 9/23 about to be replaced by a thin wrapper on top of C++17 threads ///////////////////////TICKET #1279 : consolidate to C++17 features
*/
@ -105,6 +108,7 @@
#include "lib/nocopy.hpp"
#include "include/logging.h"
#include "lib/meta/function.hpp"
#include "lib/result.hpp"
#include <thread>
#include <string>
@ -122,6 +126,10 @@ namespace lib {
namespace thread {// Thread-wrapper base implementation...
/** @internal wraps the C++ thread handle
* and provides some implementation details,
* which are then combined by the _policy template_
*/
struct ThreadWrapper
: util::MoveOnly
{
@ -153,12 +161,37 @@ namespace lib {
};
template<class BAS>
struct PolicyTODO
/**
* Thread Lifecycle Policy:
* - launch thread without further control
* - errors in thread function will only be logged
* - thread detaches before terminating
* - »grace period« for thread to terminate on shutdown
*/
template<class BAS, typename>
struct PolicyLaunchOnly
: BAS
{
using BAS::BAS;
template<class FUN, typename...ARGS>
void
perform_thread_function(FUN&& callable, ARGS&& ...args)
{
try {
// execute the actual operation in this new thread
std::invoke (std::forward<FUN> (callable), std::forward<ARGS> (args)...);
}
ERROR_LOG_AND_IGNORE (thread, "Thread function")
}
void
handle_end_of_thread()
{
BAS::threadImpl_.detach();
}
void
handle_thread_still_running()
{
@ -166,29 +199,69 @@ namespace lib {
}
};
/**
* Policy-based configuration of thread lifecycle
* Thread Lifecycle Policy:
* - thread with the ability to publish results
* - return value from the thread function will be stored
* - errors in thread function will likewise be captured and retained
* - thread *must* be joined after termination of the thread function
* @warning unjoined thread on dtor call will be a fatal error (std::terminate)
*/
template<template<class> class POL>
class ThreadLifecycle
: protected POL<ThreadWrapper>
template<class BAS, typename RES>
struct PolicyResultJoin
: BAS
{
using Policy = POL<ThreadWrapper>;
using BAS::BAS;
/** Wrapper to capture a success/failure indicator and possibly a computation result */
lib::Result<RES> result_{error::Logic{"Thread still running; need to join() first."}};
template<class FUN, typename...ARGS>
void
main (FUN&& threadFunction, ARGS&& ...args)
perform_thread_function(FUN&& callable, ARGS&& ...args)
{
static_assert (std::__or_<std::is_same<RES,void>
,std::is_constructible<RES, std::invoke_result_t<FUN,ARGS...>>>());
// perform the given operation (failsafe) within this thread and capture result...
result_ = std::move (
lib::Result{std::forward<FUN>(callable)
,std::forward<ARGS>(args)...});
}
void
handle_end_of_thread()
{
/* do nothing -- thread must be joined manually */;
}
void
handle_thread_still_running()
{
ALERT (thread, "Thread '%s' was not joined. Abort.", BAS::threadID_.c_str());
}
};
/**
* Policy-based configuration of thread lifecycle
*/
template<template<class,class> class POL, typename RES =void>
class ThreadLifecycle
: protected POL<ThreadWrapper, RES>
{
using Policy = POL<ThreadWrapper,RES>;
template<typename...ARGS>
void
invokeThreadFunction (ARGS&& ...args)
{
Policy::markThreadStart();
try {
// execute the actual operation in this new thread
std::invoke (std::forward<FUN> (threadFunction), std::forward<ARGS> (args)...);
}
ERROR_LOG_AND_IGNORE (thread, "Thread function")
//
Policy::perform_thread_function (std::forward<ARGS> (args)...);
Policy::markThreadEnd();
// if (autoTerm)
Policy::threadImpl_.detach();
Policy::handle_end_of_thread();
}
@ -216,31 +289,28 @@ namespace lib {
/** Create a new thread to execute the given operation.
* The new thread starts up synchronously, can't be cancelled and it can't be joined.
* @param threadID human readable descriptor to identify the thread for diagnostics
* @param logging_flag NoBug flag to receive diagnostics regarding the new thread
* @param operation a functor holding the code to execute within the new thread.
* Any function-like entity with signature `void(void)` is acceptable.
* @warning The operation functor will be forwarded to create a copy residing
* on the stack of the new thread; thus it can be transient, however
* anything referred through a lambda closure here must stay alive
* until the new thread terminates.
* @param threadFunction a functor holding the code to execute within the new thread.
* Any function-like entity or callable is acceptable; arguments can be given.
* @warning The operation functor and all arguments will be copied into the new thread.
* The return from this constructor _syncs-with_ the launch of the operation.
*/
template<class FUN, typename...ARGS>
ThreadLifecycle (string const& threadID, FUN&& threadFunction, ARGS&& ...args)
: Policy{threadID
, &ThreadLifecycle::main<FUN,ARGS...>, this
, &ThreadLifecycle::invokeThreadFunction<FUN,ARGS...>, this
, std::forward<FUN> (threadFunction)
, std::forward<ARGS> (args)... }
{ }
};
}//(End)base implementation.
/************************************************************************//**
* A thin convenience wrapper to simplify thread-handling. The implementation
* is backed by the C++ standard library.
* A thin convenience wrapper to simplify thread-handling.
* The implementation is backed by the C++ standard library.
* Using this wrapper...
* - removes the need to join() threads, catches and ignores exceptions.
* - allows to bind to various kinds of functions including member functions
@ -250,7 +320,7 @@ namespace lib {
* `std::terminate` afterwards, should the thread still be active then.
*/
class Thread
: public thread::ThreadLifecycle<thread::PolicyTODO>
: public thread::ThreadLifecycle<thread::PolicyLaunchOnly>
{
public:
@ -260,8 +330,6 @@ namespace lib {
/************************************************************************//**
* Variant of the [standard case](\ref Thread), requiring to wait and `join()`
* on the termination of this thread. Useful to collect results calculated
@ -271,22 +339,39 @@ namespace lib {
* @warning Thread must be joined prior to destructor invocation, otherwise
* the application is shut down immediately via `std::terminate`.
*/
template<typename RES =void>
class ThreadJoinable
: public thread::ThreadLifecycle<thread::PolicyTODO>
: public thread::ThreadLifecycle<thread::PolicyResultJoin, RES>
{
public:
using ThreadLifecycle::ThreadLifecycle;
using Impl = thread::ThreadLifecycle<thread::PolicyResultJoin, RES>;
/** put the caller into a blocking wait until this thread has terminated */
void
public:
using Impl::Impl;
/**
* put the caller into a blocking wait until this thread has terminated
* @return intermediary token signalling either success or failure.
* The caller can find out by invoking `isValid()` or `maybeThrow()`
* on this result token. Moreover, if the _thread function_ yields a
* result value, this value is copied into the token and can be retrieved
* either by type conversion, or with `get<TY>()`, `value_or(default)`
* or even with an alternative producer `or_else(λ)`.
*/
lib::Result<RES>
join ()
{
if (not threadImpl_.joinable())
if (not Impl::threadImpl_.joinable())
throw lumiera::error::Logic ("joining on an already terminated thread");
threadImpl_.join();
Impl::threadImpl_.join();
return Impl::result_;
}
};
/** deduction guide: find out about result value to capture from a generic callable. */
template<typename FUN, typename...ARGS>
ThreadJoinable (string const&, FUN&&, ARGS&&...) -> ThreadJoinable<std::invoke_result_t<FUN,ARGS...>>;

View file

@ -65,24 +65,24 @@ namespace test {
{
int contended = 0;
using Threads = lib::ScopedCollection<ThreadJoinable>;
using Threads = lib::ScopedCollection<ThreadJoinable<>>;
// Start a bunch of threads with random access pattern
Threads threads{NUM_THREADS,
[&](Threads::ElementHolder& storage)
{
storage.create<ThreadJoinable> ("Sync-ClassLock stress test"
,[&]{
for (uint i=0; i<NUM_LOOP; ++i)
{
uint delay = rand() % 10;
usleep (delay);
storage.create<ThreadJoinable<>> ("Sync-ClassLock stress test"
,[&]{
for (uint i=0; i<NUM_LOOP; ++i)
{
ClassLock<void> guard;
++contended;
uint delay = rand() % 10;
usleep (delay);
{
ClassLock<void> guard;
++contended;
}
}
}
});
});
}
};

View file

@ -126,7 +126,7 @@ namespace test{
*/
class HavocThread
{
ThreadJoinable thread_;
ThreadJoinable<> thread_;
void
doIt ()

View file

@ -156,7 +156,7 @@ namespace test{
void
waitPingPong (Token& tok)
{
typedef ThreadJoinable Thread; //////////////////////////////////////WIP
typedef ThreadJoinable<> Thread; //////////////////////////////////////WIP
Thread ping ("SyncWaiting ping", bind (&Token::getIt, &tok));
Thread pong ("SyncWaiting pong", bind (&Token::getIt, &tok));

View file

@ -16961,7 +16961,8 @@
</node>
<node COLOR="#435e98" CREATED="1523059717622" FOLDED="true" ID="ID_598506387" MODIFIED="1525124215028" TEXT="Grundstruktur">
<icon BUILTIN="info"/>
<node CREATED="1523059685611" ID="ID_1274858318" MODIFIED="1523059711165" TEXT="lib::Result">
<node CREATED="1523059685611" ID="ID_1274858318" MODIFIED="1523059711165" TEXT="es gibt bereits lib::Result">
<arrowlink COLOR="#fdfbd7" DESTINATION="ID_673181142" ENDARROW="Default" ENDINCLINATION="-862;-131;" ID="Arrow_ID_956072053" STARTARROW="None" STARTINCLINATION="-678;66;"/>
<icon BUILTIN="idea"/>
<node CREATED="1523222317789" ID="ID_223201063" MODIFIED="1523222325262" TEXT="ist ein Either-Typ">
<icon BUILTIN="idea"/>
@ -54038,9 +54039,7 @@
</node>
<node CREATED="1434128074725" HGAP="24" ID="ID_242797619" MODIFIED="1684277595333">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<b>Diff</b>-basiertes &#916;-Binding
@ -57258,6 +57257,42 @@
</node>
</node>
</node>
<node CREATED="1695850005910" ID="ID_673181142" MODIFIED="1695851233120" TEXT="&#xbb;Either&#xab; : lib::Result">
<linktarget COLOR="#fdfbd7" DESTINATION="ID_673181142" ENDARROW="Default" ENDINCLINATION="-862;-131;" ID="Arrow_ID_956072053" SOURCE="ID_1274858318" STARTARROW="None" STARTINCLINATION="-678;66;"/>
<linktarget COLOR="#fdfbd7" DESTINATION="ID_673181142" ENDARROW="Default" ENDINCLINATION="-977;134;" ID="Arrow_ID_1350491310" SOURCE="ID_1460243569" STARTARROW="None" STARTINCLINATION="-878;104;"/>
<node CREATED="1695850798876" ID="ID_944309627" MODIFIED="1695850810799" TEXT="gebaut als generischer Wrapper">
<node CREATED="1695850813548" ID="ID_1035651286" MODIFIED="1695850824213" TEXT="der Value-Type liegt also zur compile-Zeit fest"/>
<node CREATED="1695850824801" ID="ID_826042426" MODIFIED="1695850833764" TEXT="er kann aber eine beliebige Exception fangen"/>
<node CREATED="1695850834428" ID="ID_1544865707" MODIFIED="1695850857976" TEXT="und hat einen pr&#xfc;fbaren &#xbb;success&#xab; / &#xbb;failure&#xab; state"/>
</node>
<node CREATED="1695850868467" ID="ID_570550847" MODIFIED="1695850893049" TEXT="Eigenschaften">
<node CREATED="1695850893945" ID="ID_1051379159" MODIFIED="1695850911427" TEXT="Result&lt;void&gt; als Baiss (nur Exception / Erfolg)"/>
<node CREATED="1695779117581" ID="ID_505417061" MODIFIED="1695851004118" TEXT="perfect forwarding&#xa0;per direkt Konstruktor erm&#xf6;glicht">
<arrowlink COLOR="#7c86a6" DESTINATION="ID_1103669600" ENDARROW="Default" ENDINCLINATION="-1340;79;" ID="Arrow_ID_344305057" STARTARROW="None" STARTINCLINATION="-2530;150;"/>
</node>
<node CREATED="1695851007782" ID="ID_1355815987" MODIFIED="1695851113493" TEXT="Konstruktor zum Aufruf beliebiger &#xbb;callables&#xab;">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das bedeutet: man kann alles, was per std::invoke aufrufbar ist, in eine Ergebnis-Repr&#228;sentation materialisieren. Im Besonderen nivelliert das automatisch (zur compile-Zeit) die Unterscheidung void / R&#252;ckgabewert. Jedwede Exception beim Aufruf wird gefangen
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1695851116458" ID="ID_959394199" MODIFIED="1695851131276" TEXT="left-biassed (monaden-artig)">
<node CREATED="1695851159396" ID="ID_666656019" MODIFIED="1695851168759" TEXT="get&lt;TY&gt;()"/>
<node CREATED="1695851134800" ID="ID_1354531664" MODIFIED="1695851149258" TEXT="or_else(&#x3bb;)"/>
<node CREATED="1695851149966" ID="ID_1505972862" MODIFIED="1695851154705" TEXT="value_or(default)"/>
</node>
<node CREATED="1695851198847" ID="ID_1666239217" MODIFIED="1695851220353" TEXT="Wert per direkter Typkonvertierung (throws!)">
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1695851240025" ID="ID_1334071764" MODIFIED="1695851245041" TEXT="Result_test">
<icon BUILTIN="info"/>
</node>
</node>
<node CREATED="1573230287134" ID="ID_1958309835" MODIFIED="1573230291318" TEXT="Concepts">
<icon BUILTIN="hourglass"/>
<node CREATED="1573230307678" ID="ID_1856823830" MODIFIED="1573230336518" TEXT="&#xbb;Lumiera Forward Iterator&#xab; integrieren"/>
@ -78950,9 +78985,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#fed5c5" DESTINATION="ID_1859841213" ENDARROW="Default" ENDINCLINATION="1276;51;" ID="Arrow_ID_1453893581" SOURCE="ID_1803056303" STARTARROW="None" STARTINCLINATION="1738;-79;"/>
<node COLOR="#ee6e3b" CREATED="1695748033606" HGAP="157" ID="ID_1181956652" MODIFIED="1695748384597" TEXT="(das geht an mich selber)" VSHIFT="13">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Um das klar zu sagen: zwar hat Christian ein Verbot von &#187;join&#171; angedacht, aber <i>grade in dieser Frage war und bin ich absolut einer Meinung mit ihm. </i>Tats&#228;chlich war Christian sogar zur&#252;ckhaltender (&#8222;man sollte es deprecaten&#8220;) &#8212; und das hat <i>mich</i>&#160; dann auf die Idee gebracht, einen separaten &#187;Joinable&#171;-Wrapper zu schreiben. Und jetzt, viele Jahre sp&#228;ter stehe <i>ich an dem Punkt, </i>da&#223; es kein absehbares Usage-Pattern gibt, und mein Design von damals ungerchtfertigt erscheint.
@ -79123,9 +79156,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="forward"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#5b3f20" CREATED="1695583819999" ID="ID_389670039" MODIFIED="1695584410343" TEXT="Yess... die klassische L&#xf6;sung ist viel aufwendiger...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...trotzdem war ich &#252;berrascht, <i>um wie viel langsamer</i>&#160;sie ist; das kann ich mir eigentlich nur dadurch erkl&#228;ren, da&#223; die Threads <i>in einen Schlafzustand versetzt </i>werden, ggfs auch bereits schon beim Versuch, die exclusive Zone zu betreten. M&#246;glicherweise dauert es auch grunds&#228;tzlich l&#228;nger, bis ein schlafender Thread &#252;berhaupt wieder aufgeweckt wird. Die Progression scheint allerdings linear in der Zahl der Threads zu sein, w&#228;hrend die Atomic-yield-Implementierung etwas &#252;berproportional langsamer wird. Das ist jetzt aber mehr Intuition, denn jenseits von 8 Threads gibt es ja zunehmend Stau im OS-Scheduler
@ -79137,9 +79168,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695580030937" ID="ID_634357060" MODIFIED="1695580179481" TEXT="die Performance von SyncBarrier ist ad&#xe4;quat f&#xfc;r den Einsatzzweck"/>
<node CREATED="1695580048111" ID="ID_784900194" MODIFIED="1695596554665" TEXT="es ist kein Overhead beobachtbar &#x2014; jenseits der typischen Scheduling-Unsch&#xe4;rfe">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Zum einen handelt es sich um bekannte Erfahrungswerte, zumindest f&#252;r die F&#228;lle mit wenigen Threads: da&#223; zwei zusammen gestartete Threads um bis zu 0.5&#181;s auseinanderlaufen, ist erwartbar, wesentlich mehr aber nicht ohne Weiteres. Und dann l&#228;&#223;t es sich best&#228;tigen, indem die Implementierung versuchsweise auf <b>busy-wait</b>&#160;umgestellt wird &#10233; f&#252;r kleine Anzahl Threads bleiben die Me&#223;werte nahezu unver&#228;ndert (sie sind minimal schlechter, aber das System geht auch in Vollast). Das bedeutet: die beobachteten Werte stellen bereits nahezu optimales Verhalten dar, f&#252;r kleine Anzahl Threads.
@ -79236,9 +79265,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695394188133" ID="ID_1229328590" MODIFIED="1695394203632" TEXT="Umbau">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695597011139" ID="ID_125138411" MODIFIED="1695597196367" TEXT="Kopie des bestehenden Thread-Wrappers umschreiben">
<node COLOR="#338800" CREATED="1695597011139" ID="ID_125138411" MODIFIED="1695859127749" TEXT="Kopie des bestehenden Thread-Wrappers umschreiben">
<linktarget COLOR="#6ebe5a" DESTINATION="ID_125138411" ENDARROW="Default" ENDINCLINATION="43;-18;" ID="Arrow_ID_195305087" SOURCE="ID_215388471" STARTARROW="None" STARTINCLINATION="-113;6;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695597146529" ID="ID_938038908" MODIFIED="1695651348752" TEXT="std::thread liefert fast alle Funktionalit&#xe4;t">
<icon BUILTIN="idea"/>
<node COLOR="#435e98" CREATED="1695600626208" ID="ID_688465099" MODIFIED="1695602235450" TEXT="als Basisklasse sichtbar?">
@ -79247,9 +79276,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695600666050" ID="ID_642355226" MODIFIED="1695600701593" TEXT="das h&#xe4;tte aber auch den Nachteil, da&#xdf; man die join/detach()-Unterscheidung unterl&#xe4;uft"/>
<node CREATED="1695602083733" ID="ID_1989367844" MODIFIED="1695602231389" TEXT="also besser nicht exponieren &#x2014; ggfs Funktionalit&#xe4;t nachr&#xfc;sten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
YAGNI.
@ -79270,9 +79297,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695602549712" ID="ID_331491775" MODIFIED="1695602590334" TEXT="tritt nur auf, wenn die Implementierung vom Thread erbt"/>
<node CREATED="1695602592608" ID="ID_207463236" MODIFIED="1695603506751" TEXT="Gefahr: Race zwischen dem abgeleiteten Ctor und der bereits startenden Thread-Funktion">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Zwar sichert der Standard zu, da&#223; das Ende des ctor-Aufrufs <i>synchronizes_with</i>&#160; dem Start der Thread-Funktion. Streng logisch kann das aber nur f&#252;r den std::thread-Konstruktor <i>selber </i>gelten (andernfalls h&#228;tte man mit einem Sequence-Point argumentieren m&#252;ssen, und nicht mit dem ctor selber; das w&#252;rde dann aber auch wieder eine unerw&#252;nschte Statefulness einf&#252;hren, weil dann im gesamten umschlie&#223;enden Ausdruck der Thread <i>eben noch nicht l&#228;uft, </i>was das RAII-Konzept untergraben w&#252;rde).
@ -79289,9 +79314,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="idea"/>
<node CREATED="1695603514279" ID="ID_1788387529" MODIFIED="1695603548957">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
explizit eine <font face="Monospaced" color="#5e1caa">lib::SyncBarrier</font>&#160;<i>in der Implementierung </i>einbinden
@ -79314,13 +79337,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695606903540" ID="ID_1827438483" MODIFIED="1695688141495" TEXT="Textuelle Thread-Kennung setzen">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1695606903540" ID="ID_1827438483" MODIFIED="1695859113052" TEXT="Textuelle Thread-Kennung setzen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1695606935311" ID="ID_1002758793" MODIFIED="1695688125602" TEXT="nimmt jetzt einen string...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...damit man auch zusammengesetzte/formatierte Werte bauen kann
@ -79338,15 +79359,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695685265924" ID="ID_1458536316" LINK="https://stackoverflow.com/a/7989973" MODIFIED="1695685429000" TEXT="Stackoverflow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695685434157" ID="ID_68260611" MODIFIED="1695685446644" TEXT="Implementierung">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1695685434157" ID="ID_68260611" MODIFIED="1695859111067" TEXT="Implementierung">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1695688011733" ID="ID_706080445" MODIFIED="1695688040471" TEXT="Linux-spezifisch">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1695688043077" ID="ID_1889925462" MODIFIED="1695688084658">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
std::thread::native_handle() &#10236; liefert hier <font face="Monospaced" color="#ff270c">pthread_t</font>
@ -79368,9 +79387,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695607713041" ID="ID_1988127528" MODIFIED="1695607720299" TEXT="ohne Thread-Kennung"/>
<node CREATED="1695607745859" ID="ID_1296792416" MODIFIED="1695607796305" TEXT="direkt mit einem Member-Fun-Ptr">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
sollte dann den this-Typ extrahieren und den this-Ptr automatisch injizieren
@ -79380,8 +79397,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695597337839" ID="ID_1776858144" MODIFIED="1695651315240" TEXT="detach() / join-Differenzierung">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1695597337839" ID="ID_1776858144" MODIFIED="1695859098234" TEXT="detach() / join-Differenzierung">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1695647408544" ID="ID_805151848" MODIFIED="1695651308867" TEXT="isValid() bzw. bool-Check">
<icon BUILTIN="button_ok"/>
<node CREATED="1695647421701" ID="ID_1863075325" MODIFIED="1695647426362" TEXT="noch notwendig?">
@ -79392,9 +79409,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695647503234" ID="ID_1607779605" MODIFIED="1695647520450">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
der Name ist <i>nicht besonders klar</i>
@ -79408,9 +79423,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695647550628" ID="ID_90948508" MODIFIED="1695647582331" TEXT="f&#xfc;r joinable-Threads &#x27fc; sie durchlaufen einen Proze&#xdf;"/>
<node CREATED="1695647620445" ID="ID_1998559139" MODIFIED="1695647729498" TEXT="es gibt die &#xbb;Hintert&#xfc;r&#xab; mit dem protected default-Ctor">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Die hatte ich eingebaut, um f&#252;r spezialisierte abgeleitete Klassen doch noch erweiterte Zustands&#252;berg&#228;nge zu erm&#246;glichen
@ -79425,13 +79438,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1695677839257" ID="ID_1013931122" MODIFIED="1695677867799" TEXT="Problem: R&#xfc;ckgabewert von join()">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1695677839257" ID="ID_1013931122" MODIFIED="1695859029074" TEXT="Problem: R&#xfc;ckgabewert von join()">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1695677870757" ID="ID_1158604113" MODIFIED="1695678100114" TEXT="war f&#xfc;r die alte Implementierung kein Problem">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...da die Implementierung mit einem aktiven Threadpool verbunden war, gab es dort auch eine Managment-Datenstruktur; die Threadpool-Logik hat eine eventuell im Thread noch erkannte Fehlerflag dorthin gespeichert &#8212; und join() konnte diese Fehlerflag dann einfach abholen.
@ -79441,9 +79452,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695678101764" ID="ID_411970965" MODIFIED="1695678328883" TEXT="hat bisher aber nur Fehlerflags abgedeckt, keine Exceptions">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...C kennt ja keine Exceptions &#8212; und der Author des Threadpool-Frameworks hielt Exceptions f&#252;r ein bestenfalls &#252;berfl&#252;ssiges Feature, das es ganz bestimmt nicht rechtfertigt, zus&#228;tzlichen Aufwand zu treiben
@ -79453,25 +79462,24 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695678330517" ID="ID_1924651405" MODIFIED="1695678362369" TEXT="der R&#xfc;ckgabewert wurde bisher &#xfc;ber einen &#xbb;Either-Typ&#xab; dargestellt">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
gemeint ist lib::Result
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#e4f1c2" DESTINATION="ID_47372972" ENDARROW="Default" ENDINCLINATION="740;34;" ID="Arrow_ID_339818403" STARTARROW="None" STARTINCLINATION="851;32;"/>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1695679266329" ID="ID_1299395095" MODIFIED="1695679291989" TEXT="das Feature erscheint mir &#x201e;halbgar&#x201c;">
<node CREATED="1695679266329" FOLDED="true" ID="ID_1299395095" MODIFIED="1695679291989" TEXT="das Feature erscheint mir &#x201e;halbgar&#x201c;...">
<icon BUILTIN="smiley-neutral"/>
<node CREATED="1695679293241" ID="ID_782789148" MODIFIED="1695679338571" TEXT="Exceptions k&#xf6;nnten strukturierte Diagnose-Info transportieren"/>
<node CREATED="1695679339661" ID="ID_292233702" MODIFIED="1695679357836" TEXT="aber genau das wird nicht unterst&#xfc;tzt"/>
<node CREATED="1695679358706" ID="ID_1430818138" MODIFIED="1695679382617" TEXT="speziell f&#xfc;r ReturnValue wird dann eine pseudo-Exception fabriziert"/>
<node CREATED="1695679388033" ID="ID_785338496" MODIFIED="1695679526638" TEXT="das Abholen+Auswerfen von Exceptions widerspricht dem Sinn einer join()-Operation">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...und zwar im Besonderen, wenn man in einer &#187;reaping-loop&#171; alle Kind-Threads ernten m&#246;chte; dann w&#252;rde nur ein Fehler ausgeworfen, und die weiteren Kinder bleiben ungeerntet (und terminieren jetzt, mit der C++14-L&#246;sung sogar das Programm)
@ -79485,7 +79493,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695679639113" ID="ID_928695067" MODIFIED="1695679655850" TEXT="und eigentlich sollte man Futures verwenden, und nicht thread::join()"/>
</node>
</node>
<node CREATED="1695679664326" ID="ID_1421960449" MODIFIED="1695679670065" TEXT="bisher nur zwei Verwendungen in Tests">
<node CREATED="1695679664326" FOLDED="true" ID="ID_1421960449" MODIFIED="1695679670065" TEXT="bisher nur zwei Verwendungen in Tests">
<icon BUILTIN="info"/>
<node CREATED="1695679685747" ID="ID_1845700436" MODIFIED="1695679693430" TEXT="DiagnosticContext_test::verify_heavilyParallelUsage">
<node CREATED="1695679695554" ID="ID_1757482897" MODIFIED="1695679724753" TEXT="hier erscheint das Feature sinnvoll"/>
<node CREATED="1695679747450" ID="ID_787283000" MODIFIED="1695679769915" TEXT="die eigentliche Verifikation f&#xfc;r den Testfall mu&#xdf; noch im Thread erfolgen"/>
@ -79504,15 +79513,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695680809244" ID="ID_530073405" MODIFIED="1695749285205" TEXT="YAGNI &#x27f9; aufgeben?">
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695680809244" FOLDED="true" ID="ID_530073405" MODIFIED="1695859093316" TEXT="YAGNI &#x27f9; aufgeben?">
<font NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="help"/>
<icon BUILTIN="stop-sign"/>
<node CREATED="1695680837800" ID="ID_556594754" MODIFIED="1695680932789" TEXT="das ganze Thread-Join-Ged&#xf6;ns hat sich generell als nicht so gl&#xfc;cklich herausgestellt">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Das ist ein klassischer Fall f&#252;r ein Feature, das zu Beginn so offensichtlich und irre n&#252;tzlich aussieht &#8212; dann aber in der Realit&#228;t nicht wirklich &#8222;fliegt&#8220;
@ -79522,9 +79529,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695680933859" ID="ID_9664587" MODIFIED="1695680967629">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
heute bevorzugt man f&#252;r &#228;hnliche Anforderungen das <b>Future / Promise</b>&#160;- Konstrukt
@ -79535,9 +79540,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695680969567" ID="ID_854612368" MODIFIED="1695681002718" TEXT="oder man sammelt gleich Ergebnis-Nachrichten in einer Lock-free-Queue"/>
<node CREATED="1695681067025" ID="ID_1829988819" MODIFIED="1695681202200" TEXT="Fehler in Threads k&#xf6;nnen im Einzelfall sehr relevant sein &#x2014; das ist aber nix Generisches">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Denn tats&#228;chlich sind aufgetretene Fehler dann ehr schon eine Form von Zustand, den man mit einem speziellen Protokoll im Thread-Objekt erfassen und nach dem join() abfragen sollte; so kann man auch die Ergebnisse mehrerer Threads korrekt kombinieren
@ -79549,7 +79552,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695681207655" ID="ID_1998022902" MODIFIED="1695681463386" TEXT="brauche dann aber einen Ersatz f&#xfc;r die zwei Tests">
<arrowlink COLOR="#b65b7a" DESTINATION="ID_478666570" ENDARROW="Default" ENDINCLINATION="41;-72;" ID="Arrow_ID_1595086726" STARTARROW="None" STARTINCLINATION="-427;24;"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1695747229306" ID="ID_1952535260" MODIFIED="1695747238936" TEXT="am n&#xe4;chsten Tag dann wieder Zweifel">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1695747229306" FOLDED="true" ID="ID_1952535260" MODIFIED="1695747238936" TEXT="am n&#xe4;chsten Tag dann wieder Zweifel">
<icon BUILTIN="smily_bad"/>
<node BACKGROUND_COLOR="#d7cfb0" COLOR="#3fa41b" CREATED="1695747248047" ID="ID_1584465729" MODIFIED="1695747828936" TEXT="&#xbb;es ist so sch&#xf6;ne Physik&#xab;"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1695748401477" ID="ID_1245905649" MODIFIED="1695748490377" TEXT="ohne einen R&#xfc;ckgabewert wirkt die &#xbb;Joinable&#xab;-Variante insgesamt fragw&#xfc;rdig">
@ -79561,9 +79564,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node COLOR="#9b0f8e" CREATED="1695748885164" ID="ID_1477111545" MODIFIED="1695749387232" TEXT="verdammt noch einmal!!">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
<b>Knoten durchhauen</b>!
@ -79584,21 +79585,25 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695749704247" ID="ID_827179831" MODIFIED="1695776492378" TEXT="R&#xfc;ckgabewert per lib::Result">
<icon BUILTIN="pencil"/>
<node CREATED="1695749715525" ID="ID_914625209" MODIFIED="1695749847745" TEXT="das ist ein Either-Typ">
<node COLOR="#338800" CREATED="1695749704247" ID="ID_827179831" MODIFIED="1695859019302" TEXT="R&#xfc;ckgabewert per lib::Result">
<icon BUILTIN="button_ok"/>
<node CREATED="1695749715525" ID="ID_1460243569" MODIFIED="1695851233120" TEXT="das ist ein Either-Typ">
<arrowlink COLOR="#fdfbd7" DESTINATION="ID_673181142" ENDARROW="Default" ENDINCLINATION="-977;134;" ID="Arrow_ID_1350491310" STARTARROW="None" STARTINCLINATION="-878;104;"/>
<icon BUILTIN="yes"/>
<node CREATED="1695850216514" ID="ID_47372972" MODIFIED="1695850512560" TEXT="hatte ich damals genau f&#xfc;r diesen Zweck hier eingef&#xfc;hrt">
<linktarget COLOR="#e4f1c2" DESTINATION="ID_47372972" ENDARROW="Default" ENDINCLINATION="740;34;" ID="Arrow_ID_339818403" SOURCE="ID_1924651405" STARTARROW="None" STARTINCLINATION="851;32;"/>
</node>
<node COLOR="#338800" CREATED="1695749719789" ID="ID_1636786367" MODIFIED="1695776447431" TEXT="diesen modernisieren">
<node CREATED="1695850229353" ID="ID_411434486" MODIFIED="1695850236531" TEXT="...und dann sp&#xe4;ter verallgemeinert"/>
<node CREATED="1695850237105" ID="ID_543765362" MODIFIED="1695850245163" TEXT="wird jetzt bereits im GUI verwendet"/>
</node>
<node COLOR="#338800" CREATED="1695749719789" FOLDED="true" ID="ID_1636786367" MODIFIED="1695776447431" TEXT="diesen modernisieren">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1695749730882" ID="ID_720335444" MODIFIED="1695776449174" TEXT="sollte einen std::exception_ptr nehmen">
<icon BUILTIN="idea"/>
<node CREATED="1695749758416" ID="ID_1018098640" MODIFIED="1695749764076" TEXT="dieser dient als Varianten-Flag"/>
<node CREATED="1695749764647" ID="ID_160637410" MODIFIED="1695749781209">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
und kann zugleich <b>jedwede</b>&#160;Exception halten
@ -79610,9 +79615,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695749796803" ID="ID_1154699124" MODIFIED="1695749823763" TEXT="API sollte k&#xfc;nftig eine Exception als &#xbb;right value&#xab; nehmen"/>
<node CREATED="1695749825847" ID="ID_1357368217" MODIFIED="1695749841931">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
und ansonsten aber <i>left-biassed</i>&#160;sein
@ -79622,9 +79625,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node COLOR="#435e98" CREATED="1695779117581" ID="ID_313781081" MODIFIED="1695779285785">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
incl <i>perfect forwarding</i>
@ -79638,8 +79639,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695776467076" ID="ID_992547663" MODIFIED="1695776489819" TEXT="den &#xbb;Either&#xab; value (lib::Result) per policy einbringen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1695776467076" ID="ID_992547663" MODIFIED="1695859016294" TEXT="den &#xbb;Either&#xab; value (lib::Result) per policy einbringen">
<linktarget COLOR="#4a94b9" DESTINATION="ID_992547663" ENDARROW="Default" ENDINCLINATION="70;74;" ID="Arrow_ID_1159950145" SOURCE="ID_836153579" STARTARROW="None" STARTINCLINATION="245;15;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -79654,11 +79656,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695657111918" ID="ID_463997820" MODIFIED="1695657217094" TEXT="in Sub-Namespace lib::thread">
<arrowlink COLOR="#6e85a1" DESTINATION="ID_750029588" ENDARROW="Default" ENDINCLINATION="-741;56;" ID="Arrow_ID_1885189676" STARTARROW="None" STARTINCLINATION="-489;0;"/>
</node>
<node CREATED="1695747369039" ID="ID_1807166092" MODIFIED="1695770884835" TEXT="immer noch unklar und problematisch">
<node COLOR="#435e98" CREATED="1695747369039" FOLDED="true" ID="ID_1807166092" MODIFIED="1695858985050" TEXT="immer noch unklar und problematisch">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Es w&#228;re zwar so irgendwie hinzubekommen &#8212; aber <i>weit entfernt von einem guten Design.</i>
@ -79667,14 +79667,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
Ich baue hier eine auf Dauer angelegte L&#246;sung, die auch sichtbar ist und in Frage gestellt werden wird!
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1695747533905" ID="ID_990711241" MODIFIED="1695747552434" TEXT="der bool-Template-Parameter wirkt unbeholfen"/>
<node CREATED="1695747554262" ID="ID_1830373313" MODIFIED="1695747660353" TEXT="dadurch ist es erschwert, Grundbausteine in eine CPP-Unit wegzupacken">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
hab das gestern versucht &#8212; so kann das nicht stehen bleiben, das ist ja l&#228;cherlich (brauche explizite Template-Instantiierung) &#8212; zumindest solange wir keine C++-Module verwenden (C++20)
@ -79684,9 +79682,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695747673046" ID="ID_1466067755" MODIFIED="1695747692667">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
die Code-Anordnung&#160;<i>hat keinen Flow</i>
@ -79697,9 +79693,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695747880669" ID="ID_1803056303" MODIFIED="1695748482205" TEXT="die erzwungene &#xbb;Joinable&#xab;-Variante wirkt mutwillig">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Ich habe doch selber oben diese Prinzipien formuliert: eine Library-L&#246;sung sollte nicht mutwillig beschr&#228;nken, sondern eine sinnvolle Gliederung anbieten...
@ -79710,17 +79704,16 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<arrowlink COLOR="#8c5869" DESTINATION="ID_1245905649" ENDARROW="Default" ENDINCLINATION="10;123;" ID="Arrow_ID_155554446" STARTARROW="None" STARTINCLINATION="129;7;"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695748592388" ID="ID_836153579" MODIFIED="1695748632222">
<node COLOR="#435e98" CREATED="1695748592388" FOLDED="true" ID="ID_836153579" MODIFIED="1695859217832">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
also vielleicht doch <b>Policy-based-Design</b>?
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#4a94b9" DESTINATION="ID_992547663" ENDARROW="Default" ENDINCLINATION="70;74;" ID="Arrow_ID_1159950145" STARTARROW="None" STARTINCLINATION="245;15;"/>
<icon BUILTIN="help"/>
<node CREATED="1695748635886" ID="ID_859201330" MODIFIED="1695748676734" TEXT="aaber ... dann wird ja alles noch umst&#xe4;ndlicher">
<icon BUILTIN="clanbomber"/>
@ -79730,9 +79723,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695748787634" ID="ID_1593689414" MODIFIED="1695748855312">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
&#10233; wenn &#252;berhaupt, m&#252;&#223;te die Policy einen <i>mittleren Binding-Layer </i>bilden
@ -79753,12 +79744,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695749538333" ID="ID_1896384393" MODIFIED="1695749549565" TEXT="definiert alle Konstruktoren"/>
<node CREATED="1695749531182" ID="ID_1148976245" MODIFIED="1695749537508" TEXT="definiert den Destruktor"/>
<node CREATED="1695749523263" ID="ID_1222427695" MODIFIED="1695749551050" TEXT="f&#xfc;hrt eine Policy ein">
<node CREATED="1695836703221" ID="ID_1826750646" MODIFIED="1695836713503" TEXT="Umgang mit R&#xfc;ckgabewerten">
<node CREATED="1695836742647" ID="ID_1537554363" MODIFIED="1695836756035" TEXT="hier lib::Result einf&#xfc;hren">
<node CREATED="1695836703221" ID="ID_1826750646" MODIFIED="1695859209399" TEXT="Umgang mit R&#xfc;ckgabewerten">
<linktarget COLOR="#77abb7" DESTINATION="ID_1826750646" ENDARROW="Default" ENDINCLINATION="-391;34;" ID="Arrow_ID_1834673532" SOURCE="ID_1313290148" STARTARROW="None" STARTINCLINATION="203;16;"/>
<node COLOR="#435e98" CREATED="1695836742647" ID="ID_1537554363" MODIFIED="1695849764232" TEXT="hier lib::Result einf&#xfc;hren">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695836757205" ID="ID_231445329" MODIFIED="1695849015400" TEXT="die void / non-void-Unterscheidung &#x27f9; handhaben per lib::Result">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1695836757205" FOLDED="true" ID="ID_231445329" MODIFIED="1695858842909" TEXT="die void / non-void-Unterscheidung &#x27f9; handhaben per lib::Result">
<icon BUILTIN="button_ok"/>
<node CREATED="1695836841642" ID="ID_29705339" MODIFIED="1695836854994" TEXT="std::invoke mit constexpr if">
<icon BUILTIN="idea"/>
</node>
@ -79779,6 +79771,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695838556170" ID="ID_1446507689" MODIFIED="1695838569693" TEXT="setzt einen std::exception_ptr per Seiteneffekt"/>
</node>
<node COLOR="#435e98" CREATED="1695838577806" ID="ID_1120414496" MODIFIED="1695848941054" TEXT="die void / non-Void-Unterscheidung leistet der deduction-guard">
<linktarget COLOR="#aba9c1" DESTINATION="ID_1120414496" ENDARROW="Default" ENDINCLINATION="-273;13;" ID="Arrow_ID_1598212790" SOURCE="ID_1076000638" STARTARROW="None" STARTINCLINATION="96;-5;"/>
<icon BUILTIN="idea"/>
</node>
<node COLOR="#435e98" CREATED="1695848949084" ID="ID_409709339" MODIFIED="1695848979720" TEXT="Problem: Argument-loser Funktor kollidiert mit Wrapper-ctor">
@ -79788,15 +79781,35 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#732d9e" CREATED="1695851257943" ID="ID_1076000638" MODIFIED="1695851350009">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
Uh-Oh ... jetzt bin ich <b>richtig stolz</b>&#160;auf mich...
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#aba9c1" DESTINATION="ID_1120414496" ENDARROW="Default" ENDINCLINATION="-273;13;" ID="Arrow_ID_1598212790" STARTARROW="None" STARTINCLINATION="96;-5;"/>
<icon BUILTIN="ksmiletris"/>
</node>
<node COLOR="#435e98" CREATED="1695858872831" ID="ID_1986862077" MODIFIED="1695858961691" TEXT="Komplexit&#xe4;t gut versteckt">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...oder gut gegliedert; das jetzt gefundene Design trennt n&#228;mlich das Starten der Funktion, Fangen von Fehlern und Speichern von Ergebnissen als eigenen Belang ab (&#10230; lib::Result); dadurch wird die Policy nun wirklich kurz und klar
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1695836714439" ID="ID_1467866217" MODIFIED="1695836729182" TEXT="Aktionen zum Thread-Ende"/>
<node CREATED="1695836729993" ID="ID_357017376" MODIFIED="1695836738339" TEXT="Umgang mit noch laufenden Threads"/>
</node>
<node CREATED="1695749552627" ID="ID_573772960" MODIFIED="1695836690424">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<font color="#7118a9" size="4">&#9881;</font>&#160;Thread <font size="5"><b>&#10549;</b></font>&#160;<font color="#07097c" face="Monospaced">main&lt;FUN,ARGS...&gt;</font>
@ -79810,11 +79823,18 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695597475293" ID="ID_1100470933" MODIFIED="1695597482079" TEXT="invokedWithinThread()">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1695597475293" ID="ID_1100470933" MODIFIED="1695859224044" TEXT="Aufruf der Thread-Funktion">
<icon BUILTIN="button_ok"/>
<node CREATED="1695859157169" ID="ID_1142804524" MODIFIED="1695859174014" TEXT="in die Policy verlagert">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695597447169" ID="ID_35947260" MODIFIED="1695597451881" TEXT="Fehlerbehandlung">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1695859162808" ID="ID_1313290148" MODIFIED="1695859214934" TEXT="im Join-Fall an lib::Result delegiert">
<arrowlink COLOR="#77abb7" DESTINATION="ID_1826750646" ENDARROW="Default" ENDINCLINATION="-391;34;" ID="Arrow_ID_1834673532" STARTARROW="None" STARTINCLINATION="203;16;"/>
<icon BUILTIN="idea"/>
</node>
</node>
<node COLOR="#338800" CREATED="1695597447169" ID="ID_35947260" MODIFIED="1695859231223" TEXT="Fehlerbehandlung">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695394205547" ID="ID_1719816317" MODIFIED="1695394259544" TEXT="Tests umstellen und modernisieren">
@ -79940,9 +79960,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695573041485" ID="ID_103298107" MODIFIED="1695573046130" TEXT="mit 8 Threads"/>
<node CREATED="1695572829848" ID="ID_244365679" MODIFIED="1695573101478" TEXT="w&#xe4;chst stark an mit exzessiven Threads">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -79975,9 +79993,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#435e98" CREATED="1695563494966" ID="ID_1097455607" MODIFIED="1695564030911" TEXT="&#xb5; oder Nanos?">
<node CREATED="1695563815435" ID="ID_1599427397" MODIFIED="1695563845016">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
Nanos w&#228;ren die <i>nat&#252;rliche Skala</i>&#160;f&#252;r moderne PCs
@ -80017,9 +80033,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695566556126" ID="ID_945962442" MODIFIED="1695571680824" TEXT="damit beide &#xb5;Benchmark-Varianten gleich funktionieren"/>
<node CREATED="1695571739899" ID="ID_923130398" MODIFIED="1695571886589" TEXT="auch f&#xfc;r diese Variante jeweils die Index-Nr der Schleife mitgeben">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
f&#252;r den BlockFlow-Test habe ich das definitiv gebraucht, um damit eine &#187;Zeitachse&#171; zu konstruieren; und auch f&#252;r multithreaded-Tests ist das <i>innerhalb des einzelnen Thread</i>&#160;durchaus sinnvoll (&#10233; siehe SyncBarrierPerformance_test)
@ -80055,9 +80069,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695573176386" ID="ID_1046039595" MODIFIED="1695573203483" TEXT="allein die Atomics in der Barriere und die Checksum aus der Schleife gen&#xfc;gen"/>
<node CREATED="1695573208319" ID="ID_356517631" MODIFIED="1695573277276" TEXT="ohnehin w&#xe4;re in std::rand() eine Contention">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
es ist ja ein einziger Zufallszahlengenerator, und es w&#228;re eine schlechte Idee, wenn die Stdlib das nicht gegen concurrency sch&#252;tzen w&#252;rde
@ -80115,9 +80127,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695576137073" ID="ID_1395611499" MODIFIED="1695578868352">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<b>Messungen</b>(Release-Build)
@ -80154,9 +80164,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695576276750" ID="ID_790641814" MODIFIED="1695576285137" TEXT="au&#xdf;er nat&#xfc;rlich das emptySetup">
<node CREATED="1695578025523" ID="ID_1395173199" MODIFIED="1695578730778" TEXT="nochmal &#xfc;berpr&#xfc;ft: kann nicht wegoptimiert werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -80174,9 +80182,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695578041995" ID="ID_1805214429" MODIFIED="1695578839300" TEXT="auch mit Varianten wie &quot;volatile&quot; verglichen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...die f&#252;hren dann nochmal zu um den Faktor 10 gr&#246;&#223;eren Werten (was mit meiner Erfahrung konsistent ist).<br />Daher erscheint die aktuelle L&#246;sung als optimal: wir zwingen den Optimiser, die Schleife auszuf&#252;hren, weil ein Wert berechnet wird; dieser greift aber nur auf eine Variable in der Klasse zu, und mu&#223; nicht atomar, volatil oder synchronisiert sein. Mit diesem Setup kann man also auch den Einflu&#223; von Atomic-Zugriffen noch gut messen
@ -80191,9 +80197,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="broken-line"/>
<node CREATED="1695579789257" ID="ID_1993600687" MODIFIED="1695579997425" TEXT="was wir hier messen ist die &#x2205; Synchronisations-Verz&#xf6;gerung">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
wir messen, wie lange ein Thread im Durchschnitt baucht, bis er sich via SyncBarrier mit den anderen Partner-Threads synchronisiert hat. Dieser Wert ist nicht deterministisch, da die zeitliche Lage der Threads zueinander nicht deterministisch ist. Wir k&#246;nnen aber auch nicht anders messen, da der Thread typischerweise in der sync()-Funktion blockt.
@ -80203,9 +80207,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695579826996" ID="ID_1515850328" MODIFIED="1695580199504">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
&#10233; wir beobachten die Barriere bei ihrer <b>bestimmungsgem&#228;&#223;en Arbeit</b>
@ -80216,9 +80218,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1695579847753" ID="ID_1248378503" MODIFIED="1695579872734">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
&#10233; wir bekommen so <b>nicht</b>&#160;den <b>Implementierungs-Overhead</b>&#160; zu fassen
@ -89230,38 +89230,31 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
<node CREATED="1695776592132" ID="ID_1103669600" LINK="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction#Deduction_for_class_templates" MODIFIED="1695779285785" TEXT="via Class Template Argument Deduction (CTAD)">
<linktarget COLOR="#7c86a6" DESTINATION="ID_1103669600" ENDARROW="Default" ENDINCLINATION="-1340;79;" ID="Arrow_ID_344305057" SOURCE="ID_505417061" STARTARROW="None" STARTINCLINATION="-2530;150;"/>
<linktarget COLOR="#7c86a6" DESTINATION="ID_1103669600" ENDARROW="Default" ENDINCLINATION="-1340;79;" ID="Arrow_ID_171962477" SOURCE="ID_313781081" STARTARROW="None" STARTINCLINATION="-729;83;"/>
<node CREATED="1695776635546" ID="ID_536392621" MODIFIED="1695776837788" TEXT="geht normalerweise nicht &#x2014; da keine &#xbb;universelle Referenz&#xab;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Wenn man eine Klasse C&lt;T&gt; hat, und einen Konstruktur definiert, der ein T&amp;&amp; - Argument nimmt, dann ist das T bereits durch den Klassen-Templateparameter <i>festgelegt; </i>es kommt in diesem Fall nicht zu einem <i>reference collapsing, </i>sondern es handelt sich einfach um eine rvalue-Referenz T&amp;&amp;. Symptom &quot;can not bind rvalue reference to lvalue&quot;
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1695776839723" ID="ID_304077427" MODIFIED="1695776912034" TEXT="Ein Konstruktor mit separatem Template-Parameter kann nicht deduziert werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...denn in diesem Fall w&#252;rde es sich zwar um eine &#187;universelle Referenz&#171; handeln, aber der Zusammenhang zum Klassen-Template-Parameter ist nicht klar
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1695776913649" ID="ID_247930242" MODIFIED="1695777249133" TEXT="Abhilfe: expliziten deduction guide schreiben">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -89287,14 +89280,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<font face="Monospaced">&#160;&#160;Result (VAL&amp;&amp;) -&gt; Result&lt;VAL&gt;; </font>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="idea"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695777446740" ID="ID_1737574962" MODIFIED="1695778365679" TEXT="mit ist nicht klar, warum das dann funktioniert gem&#xe4;&#xdf; Standard">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Wenn ich die Beschreibung in CPPReference.com richtig verstehe, dann w&#252;rde ohne expliziten deduction guide folgender guide automatisch generiert:
@ -89381,8 +89371,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<font color="#8b2626"><b>Was ich nicht verstehe</b></font>: der gem&#228;&#223; Regeln auto-generierte Guide sieht <i>exakt genauso aus, </i>wie der Guide, den man manuell definieren mu&#223;, damit es funktioniert. Warum wird dann hier ein anderer Typ deduziert? Ich habe Experimente gemacht: ohne den manuellen deduction Guide ergibt sich f&#252;r einen &lt;initializer&gt; &#8788; int&amp;&#160;&#160;&#10236; ein deduzierter Parameter X = int&#160;&#160;(was dann nat&#252;rlich scheitert)
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="help"/>
</node>
</node>