Workforce: invoke a exit hook prior to worker termination
...essential for clean-up work, especially to drop claimed resources reliably, even in case of error.
This commit is contained in:
parent
dd62240900
commit
9ccdfa24f7
3 changed files with 65 additions and 29 deletions
|
|
@ -61,15 +61,15 @@ namespace gear {
|
|||
// using std::forward;
|
||||
using std::atomic;
|
||||
using util::unConst;
|
||||
|
||||
using std::chrono_literals::operator ""ms; /////////////WIP
|
||||
|
||||
|
||||
|
||||
namespace work {
|
||||
using std::chrono::milliseconds;
|
||||
using std::chrono_literals::operator ""ms;
|
||||
|
||||
using SIG_WorkFun = activity::Proc(void);
|
||||
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)
|
||||
|
||||
struct Config
|
||||
{
|
||||
|
|
@ -80,6 +80,7 @@ namespace gear {
|
|||
const size_t DISMISS_CYCLES = 100;
|
||||
};
|
||||
|
||||
/** Individual worker thread: repeatedly pulls the `doWork` functor */
|
||||
template<class CONF>
|
||||
class Runner
|
||||
: CONF
|
||||
|
|
@ -99,24 +100,34 @@ namespace gear {
|
|||
void
|
||||
pullWork()
|
||||
{
|
||||
ASSERT_VALID_SIGNATURE (decltype(CONF::doWork), SIG_WorkFun);
|
||||
|
||||
try {
|
||||
while (true)
|
||||
{
|
||||
activity::Proc res = CONF::doWork();
|
||||
if (emergency.load (std::memory_order_relaxed))
|
||||
break;
|
||||
if (res == activity::WAIT)
|
||||
res = idleWait();
|
||||
else
|
||||
idleCycles = 0;
|
||||
if (res != activity::PASS)
|
||||
break;
|
||||
}
|
||||
ASSERT_VALID_SIGNATURE (decltype(CONF::doWork), SIG_WorkFun);
|
||||
ASSERT_VALID_SIGNATURE (decltype(CONF::finalHook), SIG_FinalHook);
|
||||
|
||||
bool regularExit{false};
|
||||
try /* ================ pull work ===================== */
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
activity::Proc res = CONF::doWork();
|
||||
if (emergency.load (std::memory_order_relaxed))
|
||||
break;
|
||||
if (res == activity::WAIT)
|
||||
res = idleWait();
|
||||
else
|
||||
idleCycles = 0;
|
||||
if (res != activity::PASS)
|
||||
break;
|
||||
}
|
||||
regularExit = true;
|
||||
}
|
||||
ERROR_LOG_AND_IGNORE (threadpool, "defunct worker thread")
|
||||
////////////////////////////////////////////////////////////////////////////OOO very important to have a reliable exit-hook here!!!
|
||||
|
||||
try /* ================ thread-exit hook ============== */
|
||||
{
|
||||
CONF::finalHook (not regularExit);
|
||||
}
|
||||
ERROR_LOG_AND_IGNORE (threadpool, "failure in thread-exit hook")
|
||||
|
||||
thread::detach();
|
||||
}
|
||||
|
||||
|
|
@ -199,10 +210,8 @@ namespace gear {
|
|||
{
|
||||
for (auto& w : workers_)
|
||||
w.emergency.store(true, std::memory_order_relaxed);
|
||||
using namespace std::chrono_literals; ///////////////////////7///WIP
|
||||
do
|
||||
std::this_thread::sleep_for(10ms);
|
||||
while (0 < size());
|
||||
while (0 < size())
|
||||
std::this_thread::sleep_for(setup_.IDLE_WAIT);
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ namespace test {
|
|||
|
||||
namespace {
|
||||
using WorkFun = std::function<work::SIG_WorkFun>;
|
||||
using FinalFun = std::function<work::SIG_FinalHook>;
|
||||
|
||||
template<class FUN>
|
||||
auto
|
||||
|
|
@ -66,6 +67,7 @@ namespace test {
|
|||
: work::Config
|
||||
{
|
||||
WorkFun doWork;
|
||||
FinalFun finalHook = [](bool){ /*NOP*/ };
|
||||
|
||||
milliseconds IDLE_WAIT = work::Config::IDLE_WAIT;
|
||||
size_t DISMISS_CYCLES = work::Config::DISMISS_CYCLES;
|
||||
|
|
@ -74,6 +76,13 @@ namespace test {
|
|||
: doWork{std::forward<FUN> (workFun)}
|
||||
{ }
|
||||
|
||||
Setup&&
|
||||
withFinalHook (FinalFun finalFun)
|
||||
{
|
||||
finalHook = move (finalFun);
|
||||
return move(*this);
|
||||
}
|
||||
|
||||
Setup&&
|
||||
withSleepPeriod (std::chrono::milliseconds millis)
|
||||
{
|
||||
|
|
@ -246,12 +255,27 @@ namespace test {
|
|||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 9/23 ⟶ define ⟶ implement
|
||||
/** @test verify invocation of a thread-termination callback
|
||||
*/
|
||||
void
|
||||
verify_finalHook()
|
||||
{
|
||||
atomic<uint> check{0};
|
||||
atomic<activity::Proc> control{activity::PASS};
|
||||
WorkForce wof{setup([&]{ return activity::Proc(control); })
|
||||
.withFinalHook([&](bool){ ++check; })};
|
||||
|
||||
CHECK (0 == check);
|
||||
|
||||
wof.activate();
|
||||
sleep_for(10ms);
|
||||
CHECK (wof.size() == work::Config::COMPUTATION_CAPACITY);
|
||||
CHECK (0 == check);
|
||||
|
||||
control = activity::HALT;
|
||||
sleep_for(10ms);
|
||||
CHECK (0 == wof.size());
|
||||
CHECK (check == work::Config::COMPUTATION_CAPACITY);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -79925,12 +79925,15 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node COLOR="#338800" CREATED="1694016479206" ID="ID_365196266" MODIFIED="1694212927107" TEXT="Worker-Threads rufen diesen Work-Funktor immerfort auf">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</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 COLOR="#338800" CREATED="1694016497043" ID="ID_1506723557" MODIFIED="1694218954889" TEXT="Rückgabewert des Work-Funktors steuert das Worker-Thread-Verhalten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<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 COLOR="#338800" CREATED="1694218976808" ID="ID_1525105143" MODIFIED="1694218991055" TEXT="Worker-Threads rufen zuverlässig einen exit-Hook auf">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1694016646687" ID="ID_784932678" MODIFIED="1694212938476" TEXT="Speicher für Worker-Threads während deren Lebensdauer halten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
|
|
@ -80052,8 +80055,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1694212971758" ID="ID_321316770" MODIFIED="1694212980437" TEXT="brauche Konfigurierbarkeit für Test"/>
|
||||
<node CREATED="1694212996114" ID="ID_279149518" MODIFIED="1694213012580" TEXT="...denn im Realbetrieb wird man länger warten"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694098852413" ID="ID_1245257433" MODIFIED="1694099559953" TEXT="verify_finalHook">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<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"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue