Library: implement and verify SyncBarrier
This commit is contained in:
parent
6735857f3b
commit
b15281d44b
3 changed files with 69 additions and 37 deletions
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -79662,8 +79662,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1695314579779" ID="ID_643512170" MODIFIED="1695314602498" TEXT="diese muß 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="⟹ Ersatzkonstrukt zwingend notwendig">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1695315426871" ID="ID_1792980090" MODIFIED="1695484826031" TEXT="⟹ Ersatzkonstrukt zwingend notwendig">
|
||||
<node CREATED="1695334520345" ID="ID_1748880887" MODIFIED="1695334539706" TEXT="sollte dann aber eine explizite Lib-Funktionalität sein"/>
|
||||
<node CREATED="1695334551413" ID="ID_257643954" LINK="https://stackoverflow.com/a/24218922" MODIFIED="1695334594067" TEXT="man könnte ein spinning-latch mit yield verwenden">
|
||||
<icon BUILTIN="idea"/>
|
||||
|
|
@ -79699,8 +79698,8 @@ Date:   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ßt nur zur Einmal-Verwendung">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
|
|
@ -79733,9 +79732,9 @@ Date:   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:   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ü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ü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ätzlich aber sofort wünschenswert">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
nicht mutmaßen — 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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue