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:
parent
38ab5a6aa9
commit
cf7c2d1327
4 changed files with 382 additions and 10 deletions
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -79625,6 +79625,220 @@ Date:   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öglichst inline aber statisch konfigurierbar">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
das bedeutet, daß die Work-Function bereits auf Typ-Ebene definiert sein muß; eine Möglichkeit ist, sie ü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öglichst alle Steuerung durch die Worker selbst ausführen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Entsprechend dem Design-Prinzip für die Scheduler-Steuerung möchte ich einen aktivenen Management-Thread und eine Zuweisung von Aktivitä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 ⟷ Worker fällt weg"/>
|
||||
<node CREATED="1693959542377" ID="ID_1692943553" MODIFIED="1693959561266" TEXT="Steuer-Zustand im Pool wird überflü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ß 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ü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 überfahren">
|
||||
<node CREATED="1693958735548" ID="ID_752652901" MODIFIED="1693958744646" TEXT="und zwar deutlich über Wartezeit"/>
|
||||
<node CREATED="1693958745946" ID="ID_1812890716" MODIFIED="1693958773012" TEXT="und zudem noch Kapazitä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ügt nicht, daß 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ü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ßlich über Rü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önnte auch sagen, das ist eine Frage der Logik: die WorkForce ist allein, was den Scheduler <i>aktiv macht.</i> 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önnte auch ein watchdog sein">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...es wäre denkbar, daß es sich nicht um einen KILL-Switch handelt, sondern um einen Heartbeat, der z.B. aus den tick()-Aufrufen erneuert werden muß, so daß 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ß diese Flag setzen können; dieser Handler kann jedoch jederzeit greifen (nicht nur im Managment-Mode)
|
||||
</li>
|
||||
<li>
|
||||
die Implementierung der Work-Fun im Scheduler-Commutator muß darauf zugreifen, um dann den enstprechenden Rü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ß absolut zuverlä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ß Grooming-Token freigeben (sonst Deadlock mö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über kö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ß die Einträge wegräumen"/>
|
||||
<node CREATED="1693961198445" ID="ID_186444339" MODIFIED="1693961216935" TEXT="solange ein Thread läuft, muß 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öscht sich selbst aus der Storage (gefährlich)
|
||||
</li>
|
||||
<li>
|
||||
oder es hängen bereits terminierte Threads in der Storage, und jede Kapazitäts-Ermittlung muß O(n) Überprü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ä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ückgabewert des Work-Funktors steuert das Worker-Thread-Verhalten">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1694016513937" ID="ID_246253866" MODIFIED="1694016826450" TEXT="PASS ⟹ gleich erneut weiter"/>
|
||||
<node CREATED="1694016533934" ID="ID_597986426" MODIFIED="1694016555143" TEXT="WAIT ⟹ Idle-Sequenz"/>
|
||||
<node CREATED="1694016562284" ID="ID_1026875594" MODIFIED="1694016570999" TEXT="HALT ⟹ Thread terminieren"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016646687" ID="ID_784932678" MODIFIED="1694016784845" TEXT="Speicher für Worker-Threads wä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ät">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016598589" ID="ID_1104497834" MODIFIED="1694016784846" TEXT="schrittweises Erhöhen der Kapazitä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ß 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:   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:   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ü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 »barrier« 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ü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 ä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ügt nicht, nur zu lesen">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1694014851046" ID="ID_779066219" MODIFIED="1694015124815" TEXT="man muß aktiv sicherstellen, den neuen Guard-Wert zu haben">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
das bedeutet, der Check muß darauf hinauslaufen; es genügt nicht, bloß irgend einen Wert vom Guard gelesen zu haben, sondern man muß sicherstellen, daß der gelesene Wert tatsächlich aus derjenigen Operation stammen muß, 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> release
|
||||
</li>
|
||||
<li>
|
||||
acquire <i>sequenced-before</i> andere Operationen-B
|
||||
</li>
|
||||
<li>
|
||||
⟹ Operationen A  <i>happens-before </i> Operationen-B
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1694014772867" ID="ID_628358915" MODIFIED="1694014801258" TEXT="then { beliebige shared-Values lesen / ä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öllig klar in diesem Punkt (»Release-Acquire-Ordering«)"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1687788623248" ID="ID_1335631068" MODIFIED="1687788627335" TEXT="Ausführungs-Struktur">
|
||||
<node CREATED="1685029833448" ID="ID_1405359337" MODIFIED="1685029836621" TEXT="Verzweigungen">
|
||||
|
|
@ -87970,7 +88247,7 @@ Date:   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ü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ätzlich gib es eine <i>daran gebundene</i> 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> von verschiedenen Threads aus zugreifbar wären
|
||||
</li>
|
||||
<li>
|
||||
sie <b>müssen</b> aber <b>an den Guard gebunden</b> sein, und zwar durch einen conditional-Check auf den vom Guard gelesenen Wert
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Dieser Zusammenhang fußt auf den exakten Definitionen der <i>release</i>  und <i>acquire</i>-semantics und einer damit verbundenen <i>synchronizes-with</i>  Zusicherung. Das hat <i>nichts mit data-dependency zu tun!</i> Es ist egal, wie auf die "anderen" Werte vor/nach der Synchronisierung zugegriffen wird (pointer, argument, globale Variable). Sondern entscheidend ist, daß <b>dazwischen liegend</b> auf eine bestimmte Eigenschaft/Wert im Guard geprüft wird; diese Eigenschaft muß sicherstellen, daß das synchronizes-with stattgefunden hat. Zugriffe ohne diese Prüfung sind undefiniert (d.h. sie können oder können nicht einen Mix von verä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ür Zugriffe auf Payload">
|
||||
<node CREATED="1521779923346" ID="ID_725815164" MODIFIED="1521779936380" TEXT="geregelt wird Sichtbarkeit von Ä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 "zum Beispiel" x86/64
|
||||
Allerdings nicht auf einer Plattform, die ohnehin sequentiell-konsistent ist. Wie "zum Beispiel" x86/64
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
|
|
|
|||
Loading…
Reference in a new issue