Workforce: verify error handling and wait on shutdown

...seemingly the implementation is complete now
This commit is contained in:
Fischlurch 2023-09-09 03:31:46 +02:00
parent 9ccdfa24f7
commit 397ded86df
3 changed files with 119 additions and 39 deletions

View file

@ -24,8 +24,8 @@
/** @file work-force.hpp
** A pool of workers for multithreaded rendering.
**
** @see ////TODO_test usage example
** @see scheduler.cpp implementation
** @see work-force-test.cpp
** @see scheduler-commutator.hpp usage as part of the scheduler
**
** @todo WIP-WIP-WIP 6/2023 »Playback Vertical Slice«
**
@ -71,6 +71,15 @@ namespace gear {
using SIG_WorkFun = activity::Proc(void); ///< config should define callable to perform work
using SIG_FinalHook = void(bool); ///< config should define callable invoked at exit (argument: is error)
/**
* Base for configuration of the worker pool.
* In real usage, a subclass of #Config is used,
* which additionally defines the two required functors
* - `doWork` : perform a piece of work and return control code
* - `finalHook` : callback invoked at work thread termination
* Obviously these two functors are defined in a way to call into
* the actual implementation of work management (i.e. the Scheduler).
*/
struct Config
{
static const size_t COMPUTATION_CAPACITY;
@ -80,6 +89,7 @@ namespace gear {
const size_t DISMISS_CYCLES = 100;
};
/** Individual worker thread: repeatedly pulls the `doWork` functor */
template<class CONF>
class Runner
@ -148,11 +158,15 @@ namespace gear {
}//(End)namespace work
/**
/*************************************//**
* Pool of worker threads for rendering.
*
* @see SomeSystem
* @see NA_test
* @note the \tparam CONF configuration/policy base must define
* - `doWork` - the _work-functor_ (with #SIG_WorkFun)
* - `finalHook` - called at thread exit
* @see WorkForce_test
* @see SchedulerCommutator
*/
template<class CONF>
class WorkForce
@ -165,7 +179,6 @@ namespace gear {
public:
WorkForce (CONF config)
: setup_{move (config)}
, workers_{}
@ -220,8 +233,6 @@ namespace gear {
unConst(workers_).remove_if([](auto& w){ return not w.joinable(); });
return workers_.size();
}
private:
};

View file

@ -216,7 +216,7 @@ namespace test {
.withSleepPeriod (10ms)};
wof.incScale();
sleep_for(10us);
sleep_for(50us);
CHECK (1 == check);
@ -241,11 +241,11 @@ namespace test {
.dismissAfter(5)};
wof.incScale();
sleep_for(20us);
sleep_for(50us);
CHECK (1 == check);
sleep_for(10ms);
sleep_for(12ms);
CHECK (2 == check); // after one wait cycle, one further invocation
sleep_for(100ms);
@ -286,6 +286,34 @@ namespace test {
void
verify_detectError()
{
atomic<uint> check{0};
atomic<uint> errors{0};
WorkForce wof{setup ([&]{
if (++check == 555)
throw error::State("evil");
return activity::PASS;
})
.withFinalHook([&](bool isFailure)
{
if (isFailure)
++errors;
})};
CHECK (0 == check);
CHECK (0 == errors);
wof.incScale();
wof.incScale();
wof.incScale();
sleep_for(10us);
CHECK (3 == wof.size());
CHECK (0 < check);
CHECK (0 == errors);
sleep_for(200ms); // wait for the programmed disaster
CHECK (2 == wof.size());
CHECK (1 == errors);
}
@ -354,22 +382,51 @@ namespace test {
/** @test TODO
* @todo WIP 9/23 define implement
/** @test verify that the WorkForce dtor waits for all active threads to disappear
* - use a work-functor which keeps all workers blocked
* - start the WorkForce within a separate thread
* - in this separate thread, cause the WorkForce destructor to be called
* - in the outer (controlling thread) release the work-functor blocking
* - at this point, all workers return, detect shutdown and terminate
*/
void
verify_dtor_blocks()
{
}
/** @test TODO
* @todo WIP 9/23 define implement
*/
void
walkingDeadline()
{
atomic<bool> trapped{true};
auto blockingWork = [&]{
while (trapped)
/* spin */;
return activity::PASS;
};
atomic<bool> pool_scaled_up{false};
atomic<bool> shutdown_done{false};
std::thread operate{[&]{
{// nested scope...
WorkForce wof{setup (blockingWork)};
wof.activate();
sleep_for(10ms);
CHECK (wof.size() == work::Config::COMPUTATION_CAPACITY);
pool_scaled_up = true;
} // WorkForce goes out of scope => dtor called
// when reaching this point, dtor has terminated
shutdown_done = true;
operate.detach();
}};
CHECK (operate.joinable()); // operate-thread is in running state
sleep_for(100ms);
CHECK (pool_scaled_up);
CHECK (not shutdown_done); // all workers are trapped in the work-functor
// thus the destructor can't dismantle the pool
trapped = false;
sleep_for(20ms);
CHECK (shutdown_done);
CHECK (not operate.joinable()); // operate-thread has detached and terminated
}
};

View file

@ -79637,7 +79637,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
</node>
<node CREATED="1693952387244" ID="ID_713372762" MODIFIED="1693952394788" TEXT="Worker-Lebenszyklus">
<node COLOR="#338800" CREATED="1693952387244" ID="ID_713372762" MODIFIED="1694222755384" TEXT="Worker-Lebenszyklus">
<icon BUILTIN="button_ok"/>
<node CREATED="1694096144054" ID="ID_1871831859" MODIFIED="1694096180493" TEXT="Skalieren wird durch ein Bedarfs-Signal ausgel&#xf6;st"/>
<node CREATED="1694096181545" ID="ID_1507356674" MODIFIED="1694096206961" TEXT="wird beim Hochskalieren (schrittweise) erzeugt"/>
<node CREATED="1694096216352" ID="ID_1944988231" MODIFIED="1694096230206" TEXT="bekommt alle weitere Steuerung vom Work-Funktor mitgeteilt"/>
@ -79655,8 +79656,10 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html></richcontent>
</node>
</node>
<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">
<node COLOR="#435e98" CREATED="1693952433774" ID="ID_1630947367" MODIFIED="1694222737565" TEXT="Steuerung">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="info"/>
<node COLOR="#435e98" CREATED="1693952446548" FOLDED="true" ID="ID_311286578" MODIFIED="1694222772583" TEXT="alle Steuerung durch die Worker selbst ausf&#xfc;hren">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -79743,8 +79746,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</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">
<node COLOR="#435e98" CREATED="1693959754509" FOLDED="true" ID="ID_412205808" MODIFIED="1694222800988" TEXT="&#x27f9; Konsequenz">
<node COLOR="#435e98" CREATED="1693959760196" ID="ID_326565545" MODIFIED="1694222695440" 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">
@ -79829,7 +79832,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<arrowlink COLOR="#7f434f" DESTINATION="ID_1077913675" ENDARROW="Default" ENDINCLINATION="-259;8;" ID="Arrow_ID_1789073668" STARTARROW="None" STARTINCLINATION="165;-11;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694016202299" ID="ID_199990511" MODIFIED="1694016220215" TEXT="brauche eine Thread-termination-Hook">
<node COLOR="#435e98" CREATED="1694016202299" ID="ID_199990511" MODIFIED="1694222692577" 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"/>
@ -79864,8 +79867,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</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 COLOR="#338800" CREATED="1694016459017" ID="ID_445172345" MODIFIED="1694222678966" TEXT="Funktionalit&#xe4;t">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1694016464368" ID="ID_1059038394" MODIFIED="1694212930507" TEXT="statisch konfigurierbarer Work-Funktor">
<icon BUILTIN="button_ok"/>
<node COLOR="#5b280f" CREATED="1694095251355" ID="ID_612425707" MODIFIED="1694095281878" TEXT="geht nicht ohne Laufzeit-Initialisierung">
@ -79950,7 +79953,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#338800" CREATED="1694016740568" ID="ID_574870562" MODIFIED="1694172542279" TEXT="Speicher bereits terminierter Worker bereinigen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1694016756960" ID="ID_692281967" MODIFIED="1694133169711" TEXT="Destruktor mu&#xdf; blocken">
<node COLOR="#338800" CREATED="1694016756960" FOLDED="true" ID="ID_692281967" MODIFIED="1694222790757" TEXT="Destruktor mu&#xdf; blocken">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1694133119469" ID="ID_365647480" MODIFIED="1694133197057" TEXT="aber auch die Threads zum Terminieren auffordern">
<arrowlink COLOR="#4e7d89" DESTINATION="ID_1321873948" ENDARROW="Default" ENDINCLINATION="527;22;" ID="Arrow_ID_1413186514" STARTARROW="None" STARTINCLINATION="1036;0;"/>
@ -80039,8 +80042,8 @@ 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="1694098740892" ID="ID_1850596111" MODIFIED="1694099559955" TEXT="Worker-Verhalten">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1694098740892" ID="ID_1850596111" MODIFIED="1694222608888" TEXT="Worker-Verhalten">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1694098758090" ID="ID_1594595049" MODIFIED="1694174633952" TEXT="verify_pullWork: f&#xfc;hrt den Work-Funktor wiederholt aus">
<icon BUILTIN="button_ok"/>
</node>
@ -80058,8 +80061,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#338800" CREATED="1694098852413" ID="ID_1245257433" MODIFIED="1694218949291" TEXT="verify_finalHook">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098904110" ID="ID_1191232452" MODIFIED="1694099559952" TEXT="verify_detectError">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1694098904110" ID="ID_1191232452" MODIFIED="1694222607329" TEXT="verify_detectError">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098957487" ID="ID_143578534" MODIFIED="1694099563792" TEXT="Pool-Verhalten">
@ -80081,8 +80084,17 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694099160252" ID="ID_950338764" MODIFIED="1694099567838" TEXT="verify_dtor_blocks">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1694099160252" ID="ID_950338764" MODIFIED="1694222611148" TEXT="verify_dtor_blocks">
<icon BUILTIN="button_ok"/>
<node CREATED="1694222614099" ID="ID_699350369" MODIFIED="1694222671079" TEXT="knifflig zu testen">
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#435e98" CREATED="1694222624017" ID="ID_240770709" MODIFIED="1694222668595" TEXT="lasse den eigentlichen Test in separaten Thread laufen">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#435e98" CREATED="1694222638383" ID="ID_814658159" MODIFIED="1694222668596" TEXT="verwende work-Funktor, der kontrollierbar blockt">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>