Workforce: analysis and design

- investigate consistency guarantees through acquire-release
  ==> turns out we do not need a fence, but it is tantamount
      to have a guard variable and actually load and check
      the value to ensure we indeed get a happens-before

- elaborate design of the WorkForce
  + no shared control variables necessary
  + no ability to forcibly shut-down the WorkForce
  + rather, all control will be exerted through the return value
    of the Work-Functor
This commit is contained in:
Fischlurch 2023-09-06 19:18:37 +02:00
parent 38ab5a6aa9
commit cf7c2d1327
4 changed files with 382 additions and 10 deletions

View file

@ -114,11 +114,12 @@ namespace gear {
/**
* Result instruction from Activity activation.
* These codes are used by the ActivityLang to
* coordinate further processing of activity chains.
* These codes are used by the ActivityLang and WorkForce
* to coordinate further processing of activities.
*/
enum Proc {PASS ///< pass on the activation down the chain
,SKIP ///< skip rest of the Activity chain for good
,WAIT ///< nothing to do; wait and re-check for work later
,KILL ///< obliterate the complete Activity-Term and all its dependencies
,HALT ///< abandon this play / render process
};

View file

@ -59,6 +59,53 @@ namespace gear {
using std::atomic;
namespace work {
struct Config
{
};
template<class CONF>
class Runner
: std::thread
, CONF
{
public:
Runner()
: thread{}
{ }
private:
void
pullWork()
{
try {
while (true)
{
activity::Proc res = CONF::doWork();
if (res == activity::WAIT)
res = idleWait();
if (res != activity::PASS)
break;
}
}
ERROR_LOG_AND_IGNORE (threadpool, "defunct worker thread")
////////////////////////////////////////////////////////////////////////////OOO very important to have a reliable exit-hook here!!!
}
activity::Proc
idleWait()
{
using namespace std::chrono_literals; /////////////WIP
std::this_thread::sleep_for (100ms);
////////////////////////////////WIP extended inactivity detector here
return activity::PASS;
}
};
}
/**
* Pool of worker threads for rendering.
*

View file

@ -7245,7 +7245,7 @@ The primary scaling effects exploited to achieve this level of performance are t
The way other parts of the system are built, requires us to obtain a guaranteed knowledge of some job's termination. It is possible to obtain that knowledge with some limited delay, but it nees to be absoultely reliable (violations leading to segfault). The requirements stated above assume this can be achieved through //jobs with guaranteed execution.// Alternatively we could consider installing specific callbacks -- in this case the scheduler itself has to guarantee the invocation of these callbacks, even if the corresponding job fails or is never invoked. It doesn't seem there is any other option.
</pre>
</div>
<div title="SchedulerWorker" creator="Ichthyostega" modifier="Ichthyostega" created="202309041605" modified="202309041621" tags="Rendering spec draft" changecount="2">
<div title="SchedulerWorker" creator="Ichthyostega" modifier="Ichthyostega" created="202309041605" modified="202309061718" tags="Rendering spec draft" changecount="10">
<pre>The Scheduler //maintains a ''Work Force'' (a pool of workers) to perform the next [[render activities|RenderActivity]] continuously.//
Each worker runs in a dedicated thread; the Activities are arranged in a way to avoid blocking those worker threads
* IO operations are performed asynchronously {{red{planned as of 9/23}}}
@ -7256,6 +7256,24 @@ Using a pool of workers to perform small isolated steps of work atomically and i
This leads to a situation where it is more adequate to //distribute the scarce computation resources// to the tasks //sequenced in temporary and dependence order//. The computation tasks must be prepared and ordered -- but beyond that, there is not much that can be »managed« with a computation task. For this reason, the Scheduler in the Lumiera Render Engine uses a pool of workers, each providing one unit of computation resource (a »core«), and these workers will ''pull work'' actively, rather then distributing, queuing and dispatching tasks to a passive set of workers.
Moreover, the actual computation tasks, which can be parallelised, are at least by an order of magnitude more expensive than any administrative work for sorting tasks, checking dependencies and maintaining process state. This leads to a scheme where a worker first performs some »management work«, until encountering the next actual computation job, at which point the worker leaves the //management mode// and transitions into //concurrent work mode//. All workers are expected to be in work mode almost entirely most of the time, and thus we can expect not much contention between workers performing »management work« -- allowing to confine this management work to //single threaded operation,// thereby drastically reducing the complexity of management data structures and memory allocation.
!!!Regulating workers
The behaviour of individual workers is guided solely by the return-value flag from the work-functor. Consequently, no shared flags and no direct synchronisation whatsoever is required //within the {{{WorkForce}}} implementation.// -- notwithstanding the fact that the implementation //within the work-functor// obviously needs some concurrency coordination to produce these return values, since this the whole point is to invoke this functor concurrently. The following aspects of worker behaviour can be directed:
* returning {{{activity::PASS}}} instructs the worker to re-invoke the work-functor in the same thread immediately
* returning {{{activity::WAIT}}} requests an //idle-wait cycle//
* any other value, notably {{{activity::HALT}}} causes the worker to terminate
* likewise, an exception from anywhere within the worker shall terminate the worker and activate a »disaster mode«
Essentially this implies that //the workers themselves// (not some steering master) perform the management code leading to the aforementioned state directing return codes.
The ''idle-wait cycle'' involves some degree of capacity control. First off, a worker receiving the {{{activity::WAIT}}} should perform a sleep (by the OS scheduler) for some small period (configurable as Render Engine parameter). However, if a worker encounters an extended ongoing sequence of idle-wait cycles, beyond a (likewise configurable) threshold, the //worker shall terminate.// This way, the {{{WorkForce}}} gradually scales down when not used any more. On the other hand, //scaling up// is performed stepwise or in one jump, and triggered by an external control call, typically issued by the {{{Scheduler}}} in response to a signal from the {{{Player}}} indicating a newly added workload.
!!!Synchronisation and data consistency
As pointed out above, the code controlling the worker behaviour must care for data consistency when using shared state. However, in the actual usage scenario for scheduling media computations the amount of »management work« is by orders of magnitude smaller than any actual media computations. For that reason, //all management work// involving shared data structures can be performed //exclusively single-threaded.// This is achieved by acquiring the {{{GroomingToken}}} within the Scheduler control layer (Layer-2). After mutating the queues to determine the next task, this token will be dropped again, prior to engaging into the actual media computations.
Following the rules of [[C++ atomic Release-Acquire ordering|https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering]], for ensuring concurrent data consistency it is sufficient with this usage pattern to rely on a single atomic variable (used as implementation of the {{{GroomingToken}}}). All the other internal management data (notably the priority queue and the memory manager) can be implemented with ordinary memory accessible by all threads. The important part is actually to establish a »synchronises-with« relation
# managment data is processed in one thread holding the {{{GroomingToken}}}
# an atomic store is performed with {{{memory_order_release}}} (thereby dropping the token)
# now another thread can perform an atomic load with {{{memory_order_acquire}}} -- but it is essential to check and branch on the loaded value
# and only when the loaded value indicates that the load is //synchronised-with// the preceding store, then the other management data can be processed
</pre>
</div>
<div title="ScopeLocator" modifier="Ichthyostega" created="200911192145" modified="200911202035" tags="def SessionLogic">

View file

@ -79625,6 +79625,220 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1693952215256" ID="ID_532083956" MODIFIED="1693952226539" TEXT="Implementierung">
<icon BUILTIN="pencil"/>
<node CREATED="1693952247831" ID="ID_1732680738" MODIFIED="1693952374018" TEXT="Work-Function m&#xf6;glichst inline aber statisch konfigurierbar">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das bedeutet, da&#223; die Work-Function bereits auf Typ-Ebene definiert sein mu&#223;; eine M&#246;glichkeit ist, sie &#252;ber eine Config-Template-Basis einzumischen
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1693952387244" ID="ID_713372762" MODIFIED="1693952394788" TEXT="Worker-Lebenszyklus"/>
<node CREATED="1693952433774" ID="ID_1630947367" MODIFIED="1693952436665" TEXT="Steuerung">
<node CREATED="1693952446548" ID="ID_311286578" MODIFIED="1693953466417" TEXT="m&#xf6;glichst alle Steuerung durch die Worker selbst ausf&#xfc;hren">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Entsprechend dem Design-Prinzip f&#252;r die Scheduler-Steuerung m&#246;chte ich einen aktivenen Management-Thread und eine Zuweisung von Aktivit&#228;ten vermeiden
</p>
</body>
</html></richcontent>
<icon BUILTIN="yes"/>
<node CREATED="1693954286153" ID="ID_426415001" MODIFIED="1693954288784" TEXT="Vorteil">
<node CREATED="1693954302936" ID="ID_1465443197" MODIFIED="1693954542773" TEXT="kein single point of failure">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Wir vermeiden Kontrollverlust durch einen Fehler im zentralen Steuer-Thread, Verklemmungen oder Split-brain
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1693954557094" ID="ID_572342768" MODIFIED="1693954578085" TEXT="Synchronisation Master &#x27f7; Worker f&#xe4;llt weg"/>
<node CREATED="1693959542377" ID="ID_1692943553" MODIFIED="1693959561266" TEXT="Steuer-Zustand im Pool wird &#xfc;berfl&#xfc;ssig"/>
</node>
<node CREATED="1693954289281" ID="ID_818498191" MODIFIED="1693954291686" TEXT="Nachteil">
<node CREATED="1693954667743" ID="ID_423453028" MODIFIED="1693954680634" TEXT="Zugriff auf Steuerdaten ist problematisch"/>
<node CREATED="1693954694578" ID="ID_955972726" MODIFIED="1693954727243" TEXT="Steuerlogik wird undurchsichtig und komplex"/>
<node CREATED="1693959588443" ID="ID_1234469964" MODIFIED="1693959679105" TEXT="man kann den Pool nicht explizit herunterfahren">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das bedeutet auch: sein dtor mu&#223; blocken (oder laufenden Threads einfach abwerfen)
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
<node CREATED="1693953287501" ID="ID_745423803" MODIFIED="1693953706373" TEXT="Situationen">
<node CREATED="1693953529749" ID="ID_976479123" MODIFIED="1693953558062" TEXT="idle">
<node CREATED="1693958169975" ID="ID_871609453" MODIFIED="1693958187209" TEXT="Bedingung">
<node CREATED="1693958192262" ID="ID_620823816" MODIFIED="1693958482109" TEXT="f&#xfc;r aktuelle Zeit nichts (mehr) in der PriQueue">
<arrowlink COLOR="#4b5b6e" DESTINATION="ID_1094236956" ENDARROW="Default" ENDINCLINATION="232;0;" ID="Arrow_ID_1575351193" STARTARROW="None" STARTINCLINATION="180;12;"/>
</node>
<node CREATED="1693958273402" ID="ID_1304069363" MODIFIED="1693958501662" TEXT="mehrfach Wartezyklus durchalufen">
<arrowlink COLOR="#58367c" DESTINATION="ID_970175762" ENDARROW="Default" ENDINCLINATION="132;10;" ID="Arrow_ID_144131215" STARTARROW="None" STARTINCLINATION="145;12;"/>
<linktarget COLOR="#513d81" DESTINATION="ID_1304069363" ENDARROW="Default" ENDINCLINATION="-97;4;" ID="Arrow_ID_1405017857" SOURCE="ID_1094236956" STARTARROW="None" STARTINCLINATION="-20;5;"/>
</node>
</node>
<node CREATED="1693958242197" ID="ID_663637708" MODIFIED="1693958244665" TEXT="Reaktion">
<node CREATED="1693958248117" ID="ID_1094236956" MODIFIED="1693958482109" TEXT="Wartezyklus">
<arrowlink COLOR="#513d81" DESTINATION="ID_1304069363" ENDARROW="Default" ENDINCLINATION="-97;4;" ID="Arrow_ID_1405017857" STARTARROW="None" STARTINCLINATION="-20;5;"/>
<linktarget COLOR="#4b5b6e" DESTINATION="ID_1094236956" ENDARROW="Default" ENDINCLINATION="232;0;" ID="Arrow_ID_1575351193" SOURCE="ID_620823816" STARTARROW="None" STARTINCLINATION="180;12;"/>
</node>
<node CREATED="1693958393217" ID="ID_970175762" MODIFIED="1693958493702" TEXT="Worker klinkt sich aus und terminiert">
<linktarget COLOR="#58367c" DESTINATION="ID_970175762" ENDARROW="Default" ENDINCLINATION="132;10;" ID="Arrow_ID_144131215" SOURCE="ID_1304069363" STARTARROW="None" STARTINCLINATION="145;12;"/>
</node>
</node>
</node>
<node CREATED="1693953979682" ID="ID_517797186" MODIFIED="1693953983400" TEXT="slip">
<node CREATED="1693958684818" ID="ID_1376590474" MODIFIED="1693958726233" TEXT="Startzeit an Priqueue-Head &#xfc;berfahren">
<node CREATED="1693958735548" ID="ID_752652901" MODIFIED="1693958744646" TEXT="und zwar deutlich &#xfc;ber Wartezeit"/>
<node CREATED="1693958745946" ID="ID_1812890716" MODIFIED="1693958773012" TEXT="und zudem noch Kapazit&#xe4;tsreseve vorhanden"/>
</node>
<node CREATED="1693958775230" ID="ID_900516675" MODIFIED="1693958779193" TEXT="Reaktion">
<node CREATED="1693958843845" ID="ID_305158036" MODIFIED="1693959009635" TEXT="+1 Worker starten"/>
</node>
</node>
<node CREATED="1693954143549" ID="ID_1016637526" MODIFIED="1693954150160" TEXT="halt">
<node CREATED="1693959090314" ID="ID_1483418518" MODIFIED="1693959093230" TEXT="Bedingung">
<node CREATED="1693959094332" ID="ID_998114510" MODIFIED="1693959098151" TEXT="fataler Fehler">
<node CREATED="1693959216974" ID="ID_1732647360" MODIFIED="1693959240812" TEXT="es gen&#xfc;gt nicht, da&#xdf; nur ein Play-Prozess angehalten wurde"/>
<node CREATED="1693959201853" ID="ID_1303372468" MODIFIED="1693959257545" TEXT="Exception in Worker-Thread">
<arrowlink COLOR="#9c305e" DESTINATION="ID_1779736122" ENDARROW="Default" ENDINCLINATION="84;0;" ID="Arrow_ID_850804197" STARTARROW="None" STARTINCLINATION="83;9;"/>
</node>
</node>
<node CREATED="1693959098667" ID="ID_1779736122" MODIFIED="1693959252058" TEXT="oder externes Signal (Shutdown)">
<linktarget COLOR="#9c305e" DESTINATION="ID_1779736122" ENDARROW="Default" ENDINCLINATION="84;0;" ID="Arrow_ID_850804197" SOURCE="ID_1303372468" STARTARROW="None" STARTINCLINATION="83;9;"/>
</node>
</node>
<node CREATED="1693959294593" ID="ID_121256949" MODIFIED="1693959296594" TEXT="Reaktion">
<node CREATED="1693959298145" ID="ID_1788717235" MODIFIED="1693959307460" TEXT="Work-Funktion liefert HALT zur&#xfc;ck"/>
<node CREATED="1693959308832" ID="ID_1785662691" MODIFIED="1693959332563" TEXT="empfangender Worker klinkt sich aus und terminiert"/>
</node>
</node>
</node>
<node CREATED="1693959754509" ID="ID_412205808" MODIFIED="1693959759220" TEXT="Konsequenz">
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1693959760196" ID="ID_326565545" MODIFIED="1694016191857" TEXT="Steuerung erfolgt ausschlie&#xdf;lich &#xfc;ber R&#xfc;ckgabewert der WorkFun">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1693960082906" ID="ID_1717738545" MODIFIED="1693960097949" TEXT="brauche aber eine Halt-Flag">
<icon BUILTIN="messagebox_warning"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1693960109254" ID="ID_197196890" MODIFIED="1694016146788" TEXT="wegen Code-Organisation in der WorkForce anzusiedeln">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...man k&#246;nnte auch sagen, das ist eine Frage der Logik: die WorkForce ist allein, was den Scheduler <i>aktiv macht.</i>&#160;Deshalb sollte der dieser Status nicht woanders sein....
</p>
</body>
</html></richcontent>
<icon BUILTIN="help"/>
</node>
<node CREATED="1693960441858" ID="ID_1893259928" MODIFIED="1693961018338" TEXT="k&#xf6;nnte auch ein watchdog sein">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...es w&#228;re denkbar, da&#223; es sich nicht um einen KILL-Switch handelt, sondern um einen Heartbeat, der z.B. aus den tick()-Aufrufen erneuert werden mu&#223;, so da&#223; im Fall einer Verklemmung sich der Scheduler selbst terminiert
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1693960760375" ID="ID_1365275183" MODIFIED="1693960911841" TEXT="der Zugriff darauf bleibt ein Problem">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<ul>
<li>
der Exception-Handler in einem Worker-Thread mu&#223; diese Flag setzen k&#246;nnen; dieser Handler kann jedoch jederzeit greifen (nicht nur im Managment-Mode)
</li>
<li>
die Implementierung der Work-Fun im Scheduler-Commutator mu&#223; darauf zugreifen, um dann den enstprechenden R&#252;ckgabewert zu liefern, der die Worker terminiert
</li>
</ul>
</body>
</html></richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016202299" ID="ID_199990511" MODIFIED="1694016220215" TEXT="brauche eine Thread-termination-Hook">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1694016226184" ID="ID_1179993551" MODIFIED="1694016293267" TEXT="mu&#xdf; absolut zuverl&#xe4;sseig laufen als Letztes vor Terminieren des Thread">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016294919" ID="ID_240227471" MODIFIED="1694016354350" TEXT="konkrete Impl mu&#xdf; Grooming-Token freigeben (sonst Deadlock m&#xf6;glich)">
<arrowlink COLOR="#88617a" DESTINATION="ID_688462252" ENDARROW="Default" ENDINCLINATION="118;-18;" ID="Arrow_ID_953966962" STARTARROW="None" STARTINCLINATION="-312;13;"/>
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016398145" ID="ID_1137833465" MODIFIED="1694016416375" TEXT="dar&#xfc;ber k&#xf6;nnen auch fatale Fehler kommuniziert werden">
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1693961049441" ID="ID_62592237" MODIFIED="1693961124383" TEXT="das Verwalten der Thread-Allokation ist nicht einfach">
<icon BUILTIN="clanbomber"/>
<node CREATED="1693961145236" ID="ID_1855996178" MODIFIED="1693961159926" TEXT="irgendjemand mu&#xdf; die Eintr&#xe4;ge wegr&#xe4;umen"/>
<node CREATED="1693961198445" ID="ID_186444339" MODIFIED="1693961216935" TEXT="solange ein Thread l&#xe4;uft, mu&#xdf; die Allokation noch gehalten werden"/>
<node CREATED="1693961276331" ID="ID_59693591" MODIFIED="1693961456720" TEXT="die Zahl der aktiven Threads ist nicht ohne Weiteres klar">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<ul>
<li>
entweder ein terminierende Thread l&#246;scht sich selbst aus der Storage (gef&#228;hrlich)
</li>
<li>
oder es h&#228;ngen bereits terminierte Threads in der Storage, und jede Kapazit&#228;ts-Ermittlung mu&#223; O(n) &#220;berpr&#252;fungen machen
</li>
</ul>
</body>
</html></richcontent>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016459017" ID="ID_445172345" MODIFIED="1694016463233" TEXT="Funktionalit&#xe4;t">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016464368" ID="ID_1059038394" MODIFIED="1694016784845" TEXT="statisch konfigurierbarer Work-Funktor">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016479206" ID="ID_365196266" MODIFIED="1694016784845" TEXT="Worker-Threads rufen diesen Work-Funktor immerfort auf">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016497043" ID="ID_1506723557" MODIFIED="1694016784845" TEXT="R&#xfc;ckgabewert des Work-Funktors steuert das Worker-Thread-Verhalten">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1694016513937" ID="ID_246253866" MODIFIED="1694016826450" TEXT="PASS &#x27f9; gleich erneut weiter"/>
<node CREATED="1694016533934" ID="ID_597986426" MODIFIED="1694016555143" TEXT="WAIT &#x27f9; Idle-Sequenz"/>
<node CREATED="1694016562284" ID="ID_1026875594" MODIFIED="1694016570999" TEXT="HALT &#x27f9; Thread terminieren"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016646687" ID="ID_784932678" MODIFIED="1694016784845" TEXT="Speicher f&#xfc;r Worker-Threads w&#xe4;hrend deren Lebensdauer halten">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016584453" ID="ID_252099735" MODIFIED="1694016784846" TEXT="Hochfahren auf volle Kapazit&#xe4;t">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016598589" ID="ID_1104497834" MODIFIED="1694016784846" TEXT="schrittweises Erh&#xf6;hen der Kapazit&#xe4;t">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016719052" ID="ID_841238568" MODIFIED="1694016784846" TEXT="Feststellen der aktuellen Auslastung">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016740568" ID="ID_574870562" MODIFIED="1694016784847" TEXT="Speicher bereits terminierter Worker bereinigen">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016756960" ID="ID_692281967" MODIFIED="1694016784847" TEXT="Destruktor mu&#xdf; blocken">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1693841488183" HGAP="-2" ID="ID_671611566" MODIFIED="1693841514321" TEXT="WorkForce_test (Komponententest)" VSHIFT="-3">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1693864786768" ID="ID_1997885802" MODIFIED="1693864791553" TEXT="simple usage">
@ -79672,7 +79886,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1687909787970" ID="ID_1744353313" MODIFIED="1687909813720" TEXT="dieser bedient dann die Priority-Queue"/>
<node CREATED="1687909860136" ID="ID_1257565620" MODIFIED="1687910043028" TEXT="...und gibt es kooperativ wieder frei">
<linktarget COLOR="#af5678" DESTINATION="ID_1257565620" ENDARROW="Default" ENDINCLINATION="223;172;" ID="Arrow_ID_1390633196" SOURCE="ID_1887123630" STARTARROW="None" STARTINCLINATION="-430;56;"/>
<node CREATED="1687909898834" ID="ID_688462252" MODIFIED="1687909905300" TEXT="Deadlock-Gefahr">
<node CREATED="1687909898834" ID="ID_688462252" MODIFIED="1694016347114" TEXT="Deadlock-Gefahr">
<linktarget COLOR="#88617a" DESTINATION="ID_688462252" ENDARROW="Default" ENDINCLINATION="118;-18;" ID="Arrow_ID_953966962" SOURCE="ID_240227471" STARTARROW="None" STARTINCLINATION="-312;13;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687909906855" ID="ID_195997630" MODIFIED="1687909912310" TEXT="Watchdog notwendig">
@ -79682,6 +79897,68 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1687909981295" ID="ID_360021579" MODIFIED="1687909991866" TEXT="Alarm wenn letzter Tick zu lange zur&#xfc;ckliegt"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1694005255592" ID="ID_66203071" MODIFIED="1694005270787" TEXT="Fragen/Probleme">
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#435e98" CREATED="1694005273694" ID="ID_1381658042" MODIFIED="1694015491578" TEXT="sind dadurch die Inhalte in der Queue hinreichend synchronisiert?">
<icon BUILTIN="help"/>
<node CREATED="1694005322415" ID="ID_786045876" MODIFIED="1694005335066" TEXT="also: wie viel &#xbb;barrier&#xab; brauchen wir?"/>
<node CREATED="1694009756545" ID="ID_1522114869" LINK="https://en.cppreference.com/w/cpp/atomic/atomic_thread_fence" MODIFIED="1694009810286" TEXT="hinreichend: eine std::atomic_thread_fence(release) + ein atomic_read"/>
<node CREATED="1694014467032" ID="ID_1491390182" LINK="https://preshing.com/20130823/the-synchronizes-with-relation/" MODIFIED="1694014611179" TEXT="Lt. Blog(Pershing) gen&#xfc;gt bereits ein Check auf einen atomaren Guard">
<arrowlink COLOR="#576bb3" DESTINATION="ID_938834649" ENDARROW="Default" ENDINCLINATION="-563;20;" ID="Arrow_ID_1094658969" STARTARROW="None" STARTINCLINATION="-2552;100;"/>
<icon BUILTIN="idea"/>
<node CREATED="1694014702705" ID="ID_784019789" MODIFIED="1694014794006" TEXT="beliebige shared-Values &#xe4;ndern">
<icon BUILTIN="full-1"/>
</node>
<node CREATED="1694014723647" ID="ID_713413290" MODIFIED="1694014796182" TEXT="guard.store(XXX, memory_order_release)">
<icon BUILTIN="full-2"/>
</node>
<node CREATED="1694014752699" ID="ID_1786023626" MODIFIED="1694014799021" TEXT="if (XXX == guard.load(memory_order_acquire)">
<icon BUILTIN="full-3"/>
<node CREATED="1694014804964" ID="ID_1422022846" MODIFIED="1694014832342">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
die Verzweigung ist <b>essentiell</b>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1694014809708" ID="ID_1602635231" MODIFIED="1694014843153" TEXT="es gen&#xfc;gt nicht, nur zu lesen">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1694014851046" ID="ID_779066219" MODIFIED="1694015124815" TEXT="man mu&#xdf; aktiv sicherstellen, den neuen Guard-Wert zu haben">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das bedeutet, der Check mu&#223; darauf hinauslaufen; es gen&#252;gt nicht, blo&#223; irgend einen Wert vom Guard gelesen zu haben, sondern man mu&#223; sicherstellen, da&#223; der gelesene Wert tats&#228;chlich aus derjenigen Operation stammen mu&#223;, welche auf der anderen Seite (beim Producer) als letztes nach der Manipulation der Speicherinhalte stattfand...
</p>
<p>
</p>
<ul>
<li>
andere Operationen-A <i>sequenced-before</i>&#160;release
</li>
<li>
acquire <i>sequenced-before</i>&#160;andere Operationen-B
</li>
<li>
&#10233; Operationen A&#160; <i>happens-before </i>&#160;Operationen-B
</li>
</ul>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1694014772867" ID="ID_628358915" MODIFIED="1694014801258" TEXT="then { beliebige shared-Values lesen / &#xe4;ndern)">
<icon BUILTIN="full-4"/>
</node>
</node>
<node CREATED="1694015344557" ID="ID_571276241" LINK="https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering" MODIFIED="1694015377170" TEXT="auch CPP-Reference ist v&#xf6;llig klar in diesem Punkt (&#xbb;Release-Acquire-Ordering&#xab;)"/>
</node>
</node>
</node>
<node CREATED="1687788623248" ID="ID_1335631068" MODIFIED="1687788627335" TEXT="Ausf&#xfc;hrungs-Struktur">
<node CREATED="1685029833448" ID="ID_1405359337" MODIFIED="1685029836621" TEXT="Verzweigungen">
@ -87970,7 +88247,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
<node CREATED="1617648902994" ID="ID_276316646" MODIFIED="1617648906362" TEXT="C++20">
<node CREATED="1617648907316" ID="ID_899199723" MODIFIED="1617650703506" TEXT="Coroutine">
<node CREATED="1617648907316" FOLDED="true" ID="ID_899199723" MODIFIED="1617650703506" TEXT="Coroutine">
<node COLOR="#435e98" CREATED="1617648912609" ID="ID_996261679" LINK="https://lewissbaker.github.io/2017/09/25/coroutine-theory" MODIFIED="1617648936772" TEXT="Theorie und Definitionen">
<icon BUILTIN="info"/>
</node>
@ -88142,7 +88419,7 @@ class Something
</node>
</node>
<node CREATED="1636143147825" ID="ID_224980157" MODIFIED="1636143159589" TEXT="Assembly">
<node CREATED="1636143161969" ID="ID_1119605136" MODIFIED="1636143179445" TEXT="r?x : 64-Bit-Regixter"/>
<node CREATED="1636143161969" ID="ID_1119605136" MODIFIED="1636143179445" TEXT="r?x : 64-Bit-Register"/>
<node CREATED="1636143180154" ID="ID_858272401" MODIFIED="1636143194684" TEXT="e?x : 32-Bit-Sicht auf die gleichen Register">
<node CREATED="1636143276893" ID="ID_594751359" MODIFIED="1636143297151" TEXT="Zuweisungen/Laden f&#xfc;llt die oberen 32bit mit Nullen"/>
</node>
@ -88628,7 +88905,7 @@ class Something
<node CREATED="1450489421795" ID="ID_12247357" MODIFIED="1557498707240" TEXT="lives until the end of the program"/>
</node>
</node>
<node CREATED="1521779331036" FOLDED="true" ID="ID_1416813337" MODIFIED="1561827466249" TEXT="memory access ordering">
<node CREATED="1521779331036" FOLDED="true" ID="ID_1416813337" MODIFIED="1694010019286" TEXT="memory access ordering">
<linktarget COLOR="#5a6caa" DESTINATION="ID_1416813337" ENDARROW="Default" ENDINCLINATION="-1755;162;" ID="Arrow_ID_751165448" SOURCE="ID_1772115642" STARTARROW="None" STARTINCLINATION="-4287;-237;"/>
<node CREATED="1521779387708" ID="ID_663855061" MODIFIED="1521779394271" TEXT="C++ memory model"/>
<node CREATED="1521779395219" ID="ID_1890752917" MODIFIED="1521779403446" TEXT="C++11 Atomic library"/>
@ -88637,7 +88914,7 @@ class Something
<node CREATED="1521783300728" ID="ID_789225244" LINK="http://preshing.com/20120913/acquire-and-release-semantics/" MODIFIED="1521783329728" TEXT="Blog: Preshing on Programming"/>
<node CREATED="1521783335195" ID="ID_722067069" LINK="http://en.cppreference.com/w/cpp/atomic/memory_order" MODIFIED="1521783351104" TEXT="CPP-Reference"/>
</node>
<node CREATED="1521779409601" FOLDED="true" ID="ID_1607777448" MODIFIED="1576282357936" TEXT="fences vs. barriers vs ordering constraints">
<node CREATED="1521779409601" FOLDED="true" ID="ID_1607777448" MODIFIED="1694013814721" TEXT="fences vs. barriers vs ordering constraints">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -88683,7 +88960,36 @@ class Something
</node>
</node>
<node CREATED="1521779647000" ID="ID_641325372" MODIFIED="1521779651836" TEXT="constraints">
<node CREATED="1521779654007" ID="ID_1897577946" MODIFIED="1521779668209" TEXT="werden an eine (meist atomare) Guard-Variable gebunden"/>
<node CREATED="1521779654007" ID="ID_1897577946" MODIFIED="1521779668209" TEXT="werden an eine (meist atomare) Guard-Variable gebunden">
<node CREATED="1694014390628" ID="ID_610365477" MODIFIED="1694014405528" TEXT="der Zugriff (schreiben / lesen) auf den Guard ist mit dem constraint belegt"/>
<node CREATED="1694013830245" ID="ID_938834649" MODIFIED="1694014597818">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
zus&#228;tzlich gib es eine <i>daran gebundene</i>&#160;Payload aus nicht-atomaren Werten
</p>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<ul>
<li>
diese nicht-atomaren Werte sind ganz normale Speicherinhalte, die <i>potentiell</i>&#160;von verschiedenen Threads aus zugreifbar w&#228;ren
</li>
<li>
sie <b>m&#252;ssen</b>&#160;aber <b>an den Guard gebunden</b>&#160;sein, und zwar durch einen conditional-Check auf den vom Guard gelesenen Wert
</li>
</ul>
<p>
Dieser Zusammenhang fu&#223;t auf den exakten Definitionen der <i>release</i>&#160; und <i>acquire</i>-semantics und einer damit verbundenen <i>synchronizes-with</i>&#160; Zusicherung. Das hat <i>nichts mit data-dependency zu tun!</i>&#160;Es ist egal, wie auf die &quot;anderen&quot; Werte vor/nach der Synchronisierung zugegriffen wird (pointer, argument, globale Variable). Sondern entscheidend ist, da&#223; <b>dazwischen liegend</b>&#160;auf eine bestimmte Eigenschaft/Wert im Guard gepr&#252;ft wird; diese Eigenschaft mu&#223; sicherstellen, da&#223; das synchronizes-with stattgefunden hat. Zugriffe ohne diese Pr&#252;fung sind undefiniert (d.h. sie k&#246;nnen oder k&#246;nnen nicht einen Mix von ver&#228;nderten Werten sehen).
</p>
</body>
</html></richcontent>
<linktarget COLOR="#576bb3" DESTINATION="ID_938834649" ENDARROW="Default" ENDINCLINATION="-563;20;" ID="Arrow_ID_1094658969" SOURCE="ID_1491390182" STARTARROW="None" STARTINCLINATION="-2552;100;"/>
</node>
</node>
<node CREATED="1521779776975" ID="ID_594964930" MODIFIED="1521779831563" TEXT="erzeugen Relation f&#xfc;r Zugriffe auf Payload">
<node CREATED="1521779923346" ID="ID_725815164" MODIFIED="1521779936380" TEXT="geregelt wird Sichtbarkeit von &#xc4;nderungen"/>
<node CREATED="1521779943743" ID="ID_433064665" MODIFIED="1521779963241" TEXT="Payload == bestimmte nicht-atomare Variablen"/>
@ -88772,7 +89078,7 @@ class Something
</p>
<p>
Allerdinsg nicht auf einer Plattform, die ohnehin sequentiell-konsistent ist. Wie &quot;zum Beispiel&quot; x86/64
Allerdings nicht auf einer Plattform, die ohnehin sequentiell-konsistent ist. Wie &quot;zum Beispiel&quot; x86/64
</p>
</body>
</html></richcontent>