Workforce: configuration and initialisation of workers
- use a template parameter to allow for hook into local facilities (Scheduler) - pass config initialisation down through constructors
This commit is contained in:
parent
cf7c2d1327
commit
b8e52d008c
4 changed files with 258 additions and 48 deletions
|
|
@ -58,7 +58,9 @@ namespace gear {
|
|||
|
||||
// NA::~NA() { }
|
||||
|
||||
const size_t WorkForce::FULL_SIZE = util::max (std::thread::hardware_concurrency(), MINIMAL_CONCURRENCY);
|
||||
/** default value for full computing capacity is to use all (virtual) cores */
|
||||
const size_t work::Config::COMPUTATION_CAPACITY = util::max (std::thread::hardware_concurrency()
|
||||
, MINIMAL_CONCURRENCY);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@
|
|||
|
||||
#include "vault/common.hpp"
|
||||
#include "vault/gear/activity.hpp"
|
||||
#include "lib/meta/function.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
//#include "lib/symbol.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
//#include <string>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
|
@ -56,30 +56,37 @@ namespace gear {
|
|||
// using util::isnil;
|
||||
// using std::string;
|
||||
using std::move;
|
||||
// using std::forward;
|
||||
using std::atomic;
|
||||
|
||||
|
||||
namespace work {
|
||||
|
||||
using SIG_WorkFun = activity::Proc(void);
|
||||
|
||||
struct Config
|
||||
{
|
||||
|
||||
static const size_t COMPUTATION_CAPACITY;
|
||||
const size_t EXPECTED_MAX_POOL = 1.5*COMPUTATION_CAPACITY;
|
||||
};
|
||||
|
||||
template<class CONF>
|
||||
class Runner
|
||||
: std::thread
|
||||
, CONF
|
||||
: CONF
|
||||
, public std::thread
|
||||
{
|
||||
public:
|
||||
Runner()
|
||||
: thread{}
|
||||
Runner (CONF config)
|
||||
: CONF{move (config)}
|
||||
, thread{[this]{ pullWork(); }}
|
||||
{ }
|
||||
|
||||
private:
|
||||
void
|
||||
pullWork()
|
||||
{
|
||||
ASSERT_VALID_SIGNATURE (decltype(CONF::doWork), SIG_WorkFun);
|
||||
|
||||
try {
|
||||
while (true)
|
||||
{
|
||||
|
|
@ -103,7 +110,7 @@ namespace gear {
|
|||
return activity::PASS;
|
||||
}
|
||||
};
|
||||
}
|
||||
}//(End)namespace work
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -112,32 +119,29 @@ namespace gear {
|
|||
* @see SomeSystem
|
||||
* @see NA_test
|
||||
*/
|
||||
template<class CONF>
|
||||
class WorkForce
|
||||
: util::NonCopyable
|
||||
{
|
||||
using WorkFun = std::function<activity::Proc(void)>;
|
||||
using Pool = std::vector<std::thread>;
|
||||
using Pool = std::vector<work::Runner<CONF>>;
|
||||
|
||||
WorkFun workFun_;
|
||||
CONF setup_;
|
||||
Pool workers_;
|
||||
|
||||
atomic<bool> halt_{false};
|
||||
|
||||
public:
|
||||
static const size_t FULL_SIZE;
|
||||
|
||||
explicit
|
||||
WorkForce (WorkFun&& fun)
|
||||
: workFun_{move (fun)}
|
||||
WorkForce (CONF config)
|
||||
: setup_{move (config)}
|
||||
, workers_{}
|
||||
{
|
||||
workers_.reserve (1.5*FULL_SIZE);
|
||||
workers_.reserve (setup_.EXPECTED_MAX_POOL);
|
||||
}
|
||||
|
||||
~WorkForce()
|
||||
{
|
||||
try {
|
||||
deactivate();
|
||||
awaitShutdown();
|
||||
}
|
||||
ERROR_LOG_AND_IGNORE (threadpool, "defunct worker thread")
|
||||
}
|
||||
|
|
@ -146,16 +150,16 @@ namespace gear {
|
|||
void
|
||||
activate (double degree =1.0)
|
||||
{
|
||||
halt_ = false;
|
||||
size_t scale = util::max (size_t(degree*FULL_SIZE), 1u);
|
||||
size_t scale{setup_.COMPUTATION_CAPACITY};
|
||||
scale *= degree;
|
||||
scale = util::max (scale, 1u);
|
||||
for (uint i = workers_.size(); i < scale; ++i)
|
||||
workers_.emplace_back ([this]{ pullWork(); });
|
||||
workers_.emplace_back (setup_);
|
||||
}
|
||||
|
||||
void
|
||||
deactivate()
|
||||
awaitShutdown()
|
||||
{
|
||||
halt_ = true;
|
||||
for (auto& w : workers_)
|
||||
if (w.joinable())
|
||||
w.join();
|
||||
|
|
@ -163,21 +167,6 @@ namespace gear {
|
|||
}
|
||||
|
||||
private:
|
||||
void
|
||||
pullWork()
|
||||
{
|
||||
try {
|
||||
while (true)
|
||||
{
|
||||
activity::Proc res = workFun_();
|
||||
if (halt_ or res != activity::PASS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
ERROR_LOG_AND_IGNORE (threadpool, "defunct worker thread")
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
//#include <utility>
|
||||
//#include <chrono>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
using test::Test;
|
||||
|
|
@ -50,6 +51,9 @@ namespace test {
|
|||
// using lib::time::Offset;
|
||||
// using lib::time::Time;
|
||||
|
||||
namespace {
|
||||
using WorkFun = std::function<work::SIG_WorkFun>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -64,9 +68,18 @@ namespace test {
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
simpleUsage();
|
||||
walkingDeadline();
|
||||
setupLalup();
|
||||
simpleUsage();
|
||||
|
||||
verify_pullWork();
|
||||
verify_workerHalt();
|
||||
verify_workerSleep();
|
||||
verify_workerDemote();
|
||||
verify_finalHook();
|
||||
verify_detectError();
|
||||
verify_defaultPool();
|
||||
verify_scalePool();
|
||||
verify_countActive();
|
||||
verify_dtor_blocks();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -76,8 +89,15 @@ namespace test {
|
|||
simpleUsage()
|
||||
{
|
||||
atomic<uint> check{0};
|
||||
struct Setup
|
||||
: work::Config
|
||||
{
|
||||
WorkFun doWork;
|
||||
}
|
||||
setup;
|
||||
setup.doWork = [&]{ ++check; return activity::PASS; };
|
||||
|
||||
WorkForce wof{[&]{ ++check; return activity::PASS; }};
|
||||
WorkForce wof{setup};
|
||||
|
||||
CHECK (0 == check);
|
||||
|
||||
|
|
@ -90,18 +110,110 @@ namespace test {
|
|||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
walkingDeadline()
|
||||
verify_pullWork()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
setupLalup()
|
||||
verify_workerHalt()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_workerSleep()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_workerDemote()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_finalHook()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_detectError()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_defaultPool()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_scalePool()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_countActive()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
verify_dtor_blocks()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
*/
|
||||
void
|
||||
walkingDeadline()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -79627,7 +79627,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</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">
|
||||
<node COLOR="#435e98" CREATED="1693952247831" ID="ID_1732680738" LINK="#ID_391262141" MODIFIED="1694096132122" TEXT="Work-Function möglichst inline aber statisch konfigurierbar">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
|
|
@ -79637,7 +79637,24 @@ Date:   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 CREATED="1693952387244" ID="ID_713372762" MODIFIED="1693952394788" TEXT="Worker-Lebenszyklus">
|
||||
<node CREATED="1694096144054" ID="ID_1871831859" MODIFIED="1694096180493" TEXT="Skalieren wird durch ein Bedarfs-Signal ausgelö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"/>
|
||||
<node CREATED="1694096242144" ID="ID_1798309477" MODIFIED="1694096261145" TEXT="durchläuft bei Inaktivität einen konfigurierten Schlaf-Zyklus"/>
|
||||
<node CREATED="1694096262158" ID="ID_1697788425" MODIFIED="1694096536053" TEXT="beendet sich selbt bei längerandauernder Inaktivität"/>
|
||||
<node CREATED="1694096475945" ID="ID_787243685" MODIFIED="1694096502953" TEXT="ruft vor Ende zuverlässig eine hook-Funktion auf"/>
|
||||
<node CREATED="1694096411074" ID="ID_1767238" MODIFIED="1694096454253">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
klinkt sich vor Beenden aus: <font face="Monospaced" color="#6505c4">thread::detach()</font>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<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>
|
||||
|
|
@ -79751,8 +79768,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
...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>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1693960760375" ID="ID_1365275183" MODIFIED="1693960911841" TEXT="der Zugriff darauf bleibt ein Problem">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -79809,6 +79825,59 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<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 COLOR="#5b280f" CREATED="1694095251355" ID="ID_612425707" MODIFIED="1694095281878" TEXT="geht nicht ohne Laufzeit-Initialisierung">
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
<node CREATED="1694095283186" ID="ID_1780985861" MODIFIED="1694095313010" TEXT="C++ ist in dieser Hinsicht sehr konsequent"/>
|
||||
<node CREATED="1694095347089" ID="ID_1729488090" MODIFIED="1694097381098" TEXT="auch λ-captures können niemals in einen statischen Kontext eindringen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
lambda in local class 'vault::gear::test::WorkForce_test::simpleUsage()::Setup' cannot capture variables from the enclosing context
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node COLOR="#5b280f" CREATED="1694095394803" ID="ID_1858576296" MODIFIED="1694095527155" TEXT="das einzige „Schlupfloch“ wäre eine statische globale Variable">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das könnte zwar ein statischer Service sein, der dann sogar im Lebenszyklus der Applikation irgendwo konfiguriert wird
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
</node>
|
||||
<node CREATED="1694095484695" ID="ID_554742625" MODIFIED="1694095522293" TEXT="tatsächlich können wir aber problemlos vom Scheduler-Setup eine Initialisierung durchreichen">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1694095531834" ID="ID_391262141" MODIFIED="1694096132120" TEXT="also: ein Config-Objekt (Template-Param)">
|
||||
<node CREATED="1694095549375" ID="ID_1866942283" MODIFIED="1694095558928" TEXT="bietet damit einen frei wählbaren statischen Teil"/>
|
||||
<node CREATED="1694095559445" ID="ID_1320200932" MODIFIED="1694095566536" TEXT="wird aber auch als Init-Parameter durchgegeben"/>
|
||||
<node CREATED="1694095567147" ID="ID_1657187178" MODIFIED="1694095579833">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
und in jeden zu startenden Thread <b>kopiert</b>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1694095580490" ID="ID_983915877" MODIFIED="1694095780984" TEXT="und das ist gut so">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
C++ zwingt uns dazu, explizit das zu tun was ohnehin getan werden muß; da jedoch der <i>Typ </i>der Config per Template-Parameter gewählt wird, ist komplettes Inlining möglich; letztlich wird daher nur ein Pointer auf das Scheduler-Objekt in alle Threads kopiert — <i>exakt das</i>  was wir brauchen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
</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"/>
|
||||
|
|
@ -79850,6 +79919,44 @@ Date:   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 BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098758090" ID="ID_1594595049" MODIFIED="1694099559952" TEXT="verify_pullWork: führt den Work-Funktor wiederholt aus">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098814770" ID="ID_495507864" MODIFIED="1694099559955" TEXT="verify_workerHalt: terminiert auf Anweisung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098789389" ID="ID_1077314922" MODIFIED="1694099559954" TEXT="verify_workerSleep: schläft auf Anweisung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098829216" ID="ID_358493866" MODIFIED="1694099559953" TEXT="verify_workerDemote: terminiert nach längerem Schlaf">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098852413" ID="ID_1245257433" MODIFIED="1694099559953" TEXT="verify_finalHook">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098904110" ID="ID_1191232452" MODIFIED="1694099559952" TEXT="verify_detectError">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098957487" ID="ID_143578534" MODIFIED="1694099563792" TEXT="Pool-Verhalten">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694099014497" ID="ID_1877110298" MODIFIED="1694099563791" TEXT="verify_default: default macht nichts">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694099055410" ID="ID_1489311533" MODIFIED="1694099565281" TEXT="verify_scaleUp">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1694099029004" ID="ID_910692339" MODIFIED="1694099041032" TEXT="skaliert auf genau N worker"/>
|
||||
<node CREATED="1694099061344" ID="ID_758198253" MODIFIED="1694099067644" TEXT="skaliert um einen Worker hoch"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694099080950" ID="ID_542625093" MODIFIED="1694099566207" TEXT="verify_countActive: ermittelt Zahl aktiver Worker">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694099160252" ID="ID_950338764" MODIFIED="1694099567838" TEXT="verify_dtor_blocks">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue