UI-Dispatch: get the multithreded test to work (#1098)

the (trivial) implementation turned out to be correct as written,
but it was (again) damn challenging to get the mulithreaded chaotic
test fixture and especially the lambda captures to work correct.
This commit is contained in:
Fischlurch 2017-08-07 01:00:36 +02:00
parent a7ad82c935
commit 46fc900980
3 changed files with 57 additions and 39 deletions

View file

@ -51,7 +51,12 @@ return: 0
END
TEST "LifeCycle_test" LifeCycle_test <<END
TEST "Dispatch functors into other threads" CallQueue_test <<END
return: 0
END
TEST "Application Lifecycle hooks" LifeCycle_test <<END
return: 0
END
@ -152,7 +157,7 @@ return: 0
END
TEST "Defining Suppport for specific timecode formats" FormatSupport_test <<END
TEST "Suppport for specific timecode formats" FormatSupport_test <<END
return: 0
END

View file

@ -26,11 +26,10 @@
#include "lib/test/run.hpp"
#include "lib/util.hpp"
#include "lib/format-cout.hpp"
#include "lib/scoped-collection.hpp"
#include "backend/thread-wrapper.hpp"
#include "lib/sync.hpp"
#include "lib/util.hpp"
#include "lib/call-queue.hpp"
@ -43,7 +42,6 @@ namespace lib {
namespace test{
using lib::Sync;
using backend::Thread;
using backend::ThreadJoinable;
using util::isnil;
@ -58,9 +56,9 @@ namespace test{
uint const NUM_OF_THREADS = 50;
uint const MAX_RAND_INCMT = 200;
uint const MAX_RAND_STEPS = 500;
uint const MAX_RAND_DELAY = 10000;
uint const MAX_RAND_DELAY = 1000;
// --------random-stress-test------
uint calc_sum = 0;
uint ctor_sum = 0;
@ -109,7 +107,7 @@ namespace test{
*
* @see lib::CallQueue
* @see gui::NotificationService usage example
* @see [DemoGuiRoundtrip]: http://issues.lumiera.org/ticket/1099 "Ticket #1099"
* @see [DemoGuiRoundtrip](http://issues.lumiera.org/ticket/1099 "Ticket #1099")
*/
class CallQueue_test : public Test
{
@ -182,18 +180,34 @@ namespace test{
using Step = std::function<uint()>;
struct Worker
: ThreadJoinable
, Sync<>
{
uint64_t localSum = 0;
uint64_t producerSum = 0;
uint64_t consumerSum = 0;
Worker(uint cnt, Step workStep)
void
countConsumerCall (uint increment)
{
Lock sync(this); // NOTE: will be invoked from some random other thread
consumerSum += increment;
}
Worker(CallQueue& queue)
: ThreadJoinable{"CallQueue_test: concurrent dispatch"
, [&]() {
uint cnt = rand() % MAX_RAND_STEPS;
uint delay = rand() % MAX_RAND_DELAY;
for (uint i=0; i<cnt; ++i)
localSum += workStep();
{
uint increment = rand() % MAX_RAND_INCMT;
queue.feed ([=]() { countConsumerCall(increment); });
producerSum += increment;
usleep (delay);
queue.invoke(); // NOTE: dequeue one functor added during our sleep
} // and thus belonging to some random other thread
}}
{ }
};
@ -201,43 +215,40 @@ namespace test{
using Workers = lib::ScopedCollection<Worker>;
/**
* @test torture the CallQueue by massively multithreaded dispatch
* - start #NUM_OF_THREADS (e.g. 50) threads in parallel
* - each of those has a randomised execution pattern to
* add new functors and dispatch other thread's functors
*/
void
verify_ThreadSafety()
{
CallQueue queue;
uint64_t globalSum = 0;
uint64_t checkSum = 0;
Step step =[&]() -> uint
{
uint increment = rand() % MAX_RAND_INCMT;
uint delay = rand() % MAX_RAND_DELAY;
queue.feed ([&]() { globalSum += increment; });
usleep (delay);
queue.invoke(); // NOTE: typically this dequeues some other entry added during our sleep
return increment;
};
uint const cntSteps = rand() % MAX_RAND_STEPS;
// Start a bunch of threads with random access pattern
Workers workers{NUM_OF_THREADS,
[&](Workers::ElementHolder& storage)
{
storage.create<Worker>(cntSteps, step);
storage.create<Worker>(queue);
}
};
// wait for termination of all threads
for (auto& worker : workers)
worker.join();
// collect the results of all worker threads
uint64_t globalProducerSum = 0;
uint64_t globalConsumerSum = 0;
for (auto& worker : workers)
{
worker.join();
checkSum += worker.localSum;
globalProducerSum += worker.producerSum;
globalConsumerSum += worker.consumerSum;
}
// VERIFY: locally recorded partial sums match total sum
CHECK (globalSum == checkSum);
CHECK (globalProducerSum == globalConsumerSum);
}
};

View file

@ -38,8 +38,8 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1501940591109" ID="ID_1925240675" MODIFIED="1501940773195" TEXT="#1099 DemoGuiRoundtrip">
<arrowlink COLOR="#e5e53f" DESTINATION="ID_1007296291" ENDARROW="Default" ENDINCLINATION="-767;134;" ID="Arrow_ID_1440938291" STARTARROW="None" STARTINCLINATION="-51;592;"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1501940591109" ID="ID_1925240675" MODIFIED="1502075967876" TEXT="#1099 DemoGuiRoundtrip">
<arrowlink COLOR="#e5e53f" DESTINATION="ID_1007296291" ENDARROW="Default" ENDINCLINATION="-931;34;" ID="Arrow_ID_1440938291" STARTARROW="None" STARTINCLINATION="-51;592;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1501940627280" ID="ID_1675066241" MODIFIED="1501940632019" TEXT="Dummy-Code im UI"/>
<node CREATED="1501940632871" ID="ID_189611570" MODIFIED="1501940638539" TEXT="Dummy Proc-Command"/>
@ -1047,18 +1047,20 @@
</node>
<node CREATED="1501939193031" HGAP="3" ID="ID_1045913810" MODIFIED="1501939200829" TEXT="Test" VSHIFT="20">
<icon BUILTIN="pencil"/>
<node CREATED="1501939204166" ID="ID_383444966" MODIFIED="1501946866881" TEXT="CallQueue_test">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1501939204166" ID="ID_383444966" MODIFIED="1502075950777" TEXT="CallQueue_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1501946847700" ID="ID_1917302142" MODIFIED="1501951434466" TEXT="basic">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1501946852555" ID="ID_1617455971" MODIFIED="1501951436667" TEXT="mehrere">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1501946856587" ID="ID_1780067399" MODIFIED="1501946862958" TEXT="Stre&#xdf;"/>
<node COLOR="#338800" CREATED="1501946856587" ID="ID_1780067399" MODIFIED="1502075941722" TEXT="Stre&#xdf;">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1501939212693" ID="ID_1007296291" MODIFIED="1501940740143" TEXT="#1099 DemoGuiRoundtrip">
<linktarget COLOR="#e5e53f" DESTINATION="ID_1007296291" ENDARROW="Default" ENDINCLINATION="-767;134;" ID="Arrow_ID_1440938291" SOURCE="ID_1925240675" STARTARROW="None" STARTINCLINATION="-51;592;"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1501939212693" ID="ID_1007296291" MODIFIED="1502075967876" TEXT="#1099 DemoGuiRoundtrip">
<linktarget COLOR="#e5e53f" DESTINATION="ID_1007296291" ENDARROW="Default" ENDINCLINATION="-931;34;" ID="Arrow_ID_1440938291" SOURCE="ID_1925240675" STARTARROW="None" STARTINCLINATION="-51;592;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1501939235834" ID="ID_1160414548" MODIFIED="1501939239653" TEXT="Men&#xfc;-Eintrag"/>
<node CREATED="1501939240217" ID="ID_325602880" MODIFIED="1501939252187" TEXT="triggert Proc-Command"/>