Library: implement and verify SyncBarrier

This commit is contained in:
Fischlurch 2023-09-23 18:05:17 +02:00
parent 6735857f3b
commit b15281d44b
3 changed files with 69 additions and 37 deletions

View file

@ -48,7 +48,7 @@
//#include "lib/meta/function.hpp"
//#include "lib/result.hpp"
//#include <utility>
#include <thread>
#include <atomic>
@ -62,20 +62,37 @@ namespace lib {
/**
* @todo write type comment
* A one time N-fold mutual synchronisation barrier.
* Calls to #sync() will block until N such calls occurred.
* @note The blocking wait is implemented by a check-and-`yield()` loop,
* increasing load at the OS scheduler, possibly starving the system
* when stretched out over extended time.
* @remark intended use is to allow all participants to catch up and reach
* a well defined point with initialisation or implementation logic.
*/
class SyncBarrier
: util::NonCopyable
{
std::atomic_int latch_;
public:
/** @param nFold the number of participants to sync */
explicit
SyncBarrier (size_t nFold =2)
{ }
SyncBarrier (uint nFold =2)
: latch_{int(nFold)}
{
REQUIRE (nFold >= 2, "Pointless to sync less than two participants.");
}
void
sync()
{
UNIMPLEMENTED ("count-down latch logic");
size_t level = latch_.fetch_add(-1, std::memory_order_acq_rel);
if (1 < level)
do std::this_thread::yield();
while (0 < latch_.load (std::memory_order_relaxed));
else
latch_.store (0, std::memory_order_relaxed);
}
};

View file

@ -26,15 +26,10 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
//#include "lib/thread.hpp"
#include "lib/sync-barrier.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/util-foreach.hpp"
#include "lib/error.hpp"
//#include <utility>
#include <chrono>
#include <thread>
#include <atomic>
@ -43,9 +38,9 @@
using test::Test;
using util::and_all;
using lib::explore;
using std::atomic_uint;
using std::array;
using std::atomic_uint;
using std::this_thread::sleep_for;
using namespace std::chrono_literals;
@ -53,7 +48,7 @@ using namespace std::chrono_literals;
namespace lib {
namespace test {
namespace {
namespace {// Test setup for a concurrent calculation with checksum....
const uint NUM_THREADS = 1024;
@ -61,7 +56,7 @@ namespace test {
atomic_uint stage2{0};
atomic_uint finish{0};
SyncBarrier interThread{NUM_THREADS};
SyncBarrier interThread{NUM_THREADS };
SyncBarrier afterThread{NUM_THREADS+1};
/**
@ -76,18 +71,18 @@ namespace test {
public:
TestThread()
: thread{[&]()
{ //-STAGE-1------------------------------
localSum = rand() % 1000; // generate local value
stage1.fetch_add (localSum); // book in local value
interThread.sync(); // wait for all other threads to have booked in
{ //-STAGE-1------------------------------
localSum = rand() % 1000; // generate local value
stage1.fetch_add (localSum); // book in local value
interThread.sync(); // wait for all other threads to have booked in
//-STAGE-2------------------------------
localSum += stage1; // pick up compounded sum from STAGE-1
localSum += rand() % 1000; // add further local value for STAGE-2
stage2.fetch_add (localSum); // book in local sum
afterThread.sync(); // wait for other threads and supervisor
//-STAGE-2------------------------------
uint sync = stage1; // pick up compounded sum from STAGE-1
localSum += rand() % 1000; // add further local value for STAGE-2
stage2.fetch_add (localSum+sync); // book in both local values and synced sum
afterThread.sync(); // wait for other threads and supervisor
finish.fetch_add(1); // mark completion of this thread
finish.fetch_add(1); // mark completion of this thread
thread::detach(); //////////////////////////////////////////////OOO Wech-oh
}}
{ }
@ -97,7 +92,7 @@ namespace test {
};
/** sum up all `localSum` fields from all TestThread instances in a container */
/** sum up all `localSum` fields from all TestThread instances in a container */
template<class CON>
uint
sumLocals (CON const& threads)
@ -107,12 +102,17 @@ namespace test {
.foreach ([&](TestThread const& t){ sum += t.localSum; });
return sum;
}
}
}//(End)Test setup
/*******************************************************************//**
* @test verify N-fold synchronisation points by multi-thread loat-test.
*
* - start a _huge number_ of TestThread
* - all those pick up the partial sum from stage1
* @remark without coordinated synchronisation, some threads would see
* an incomplete sum and thus the stage2 checksum would be lower
* @see lib::SyncBarrier
* @see steam::control::DispatcherLoop
*/
@ -128,7 +128,7 @@ namespace test {
CHECK (and_all (threads, [](auto& t){ return t.isRunning(); }));
afterThread.sync();
sleep_for (1ms); // give the threads a chance to terminate
sleep_for (5ms); // give the threads a chance to terminate
CHECK (NUM_THREADS == finish); // all threads have passed out....
CHECK (0 < stage1);

View file

@ -79662,8 +79662,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695314579779" ID="ID_643512170" MODIFIED="1695314602498" TEXT="diese mu&#xdf; initialisiert sein, bevor der Session-Thread ihre Logik verwendet"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695315426871" ID="ID_1792980090" MODIFIED="1695315442534" TEXT="&#x27f9; Ersatzkonstrukt zwingend notwendig">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1695315426871" ID="ID_1792980090" MODIFIED="1695484826031" TEXT="&#x27f9; Ersatzkonstrukt zwingend notwendig">
<node CREATED="1695334520345" ID="ID_1748880887" MODIFIED="1695334539706" TEXT="sollte dann aber eine explizite Lib-Funktionalit&#xe4;t sein"/>
<node CREATED="1695334551413" ID="ID_257643954" LINK="https://stackoverflow.com/a/24218922" MODIFIED="1695334594067" TEXT="man k&#xf6;nnte ein spinning-latch mit yield verwenden">
<icon BUILTIN="idea"/>
@ -79699,8 +79698,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<arrowlink COLOR="#6493ca" DESTINATION="ID_1673241488" ENDARROW="Default" ENDINCLINATION="210;16;" ID="Arrow_ID_2380452" STARTARROW="None" STARTINCLINATION="10;28;"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1695391836532" ID="ID_373841600" MODIFIED="1695410342100" TEXT="lib::SyncBarrier implementieren">
<icon BUILTIN="flag-pink"/>
<node COLOR="#338800" CREATED="1695391836532" ID="ID_373841600" MODIFIED="1695484696067" TEXT="lib::SyncBarrier implementieren">
<icon BUILTIN="button_ok"/>
<node CREATED="1695391870343" ID="ID_500508570" MODIFIED="1695392284932" TEXT="bewu&#xdf;t nur zur Einmal-Verwendung">
<richcontent TYPE="NOTE"><html>
<head/>
@ -79733,9 +79732,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#6493ca" DESTINATION="ID_1673241488" ENDARROW="Default" ENDINCLINATION="210;16;" ID="Arrow_ID_2380452" SOURCE="ID_938671107" STARTARROW="None" STARTINCLINATION="10;28;"/>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695392426479" ID="ID_281891239" MODIFIED="1695394808033" TEXT="Test per Load-Test">
<node COLOR="#338800" CREATED="1695392426479" ID="ID_281891239" MODIFIED="1695484818803" TEXT="Test per Load-Test">
<arrowlink COLOR="#2b3fa9" DESTINATION="ID_1220273122" ENDARROW="Default" ENDINCLINATION="169;-7;" ID="Arrow_ID_1739726561" STARTARROW="None" STARTINCLINATION="15;204;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -79838,14 +79837,30 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695394744028" ID="ID_1755648327" MODIFIED="1695394746744" TEXT="ThreadWrapperSelfRecognitionTest_test">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1695394753483" ID="ID_1338410455" MODIFIED="1695410354252" TEXT="SyncBarrier_test">
<icon BUILTIN="flag-pink"/>
<node CREATED="1695394763010" ID="ID_1220273122" MODIFIED="1695394801458" TEXT="neuer Test f&#xfc;r neue (interims-) Implementierung">
<node COLOR="#338800" CREATED="1695394753483" ID="ID_1338410455" MODIFIED="1695484708443" TEXT="SyncBarrier_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1695394763010" ID="ID_1220273122" MODIFIED="1695484703977" TEXT="neuer Test f&#xfc;r neue (interims-) Implementierung">
<linktarget COLOR="#2b3fa9" DESTINATION="ID_1220273122" ENDARROW="Default" ENDINCLINATION="169;-7;" ID="Arrow_ID_1739726561" SOURCE="ID_281891239" STARTARROW="None" STARTINCLINATION="15;204;"/>
<icon BUILTIN="info"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695394861413" ID="ID_1334580079" MODIFIED="1695394870676" TEXT="ggfs auch gleich Performance-Test vorbereiten">
<node COLOR="#435e98" CREATED="1695394861413" ID="ID_1334580079" MODIFIED="1695484809827" TEXT="ggfs auch gleich Performance-Test vorbereiten">
<icon BUILTIN="help"/>
<node CREATED="1695484718567" ID="ID_1410950559" MODIFIED="1695484726450" TEXT="wird dann aber zu komplex"/>
<node CREATED="1695484727006" ID="ID_1647325641" MODIFIED="1695484735937" TEXT="Performance-Test braucht andere Zielsetzung"/>
<node CREATED="1695484752994" ID="ID_53306211" MODIFIED="1695484793336" TEXT="grunds&#xe4;tzlich aber sofort w&#xfc;nschenswert">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
nicht mutma&#223;en &#8212; messen!
</p>
</body>
</html></richcontent>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695484736861" ID="ID_1096160672" MODIFIED="1695484749068" TEXT="als separaten Test realisieren">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
</node>