A monitor primitive.
A monitor has a value, which can be monitored to reach a certain state. The caller is blocked until the condition is fulfilled. The concept is similar to a pthread condition, with more usage convenience.
#define TEST_RUNTIME 300 // seconds
#include <lunchbox/test.h>
#include <iostream>
#include <lunchbox/clock.h>
#include <lunchbox/monitor.h>
#include <lunchbox/thread.h>
using servus::uint128_t;
{
public:
explicit Thread1(int64_t loops)
: _loops(loops)
{
}
virtual ~Thread1() {}
virtual void run()
{
int64_t nOps = _loops;
while (nOps--)
{
monitor = -nOps;
}
std::cout << 2 * _loops / time << " ops/ms" << std::endl;
}
private:
int64_t _loops;
};
void testSimpleMonitor()
{
TEST(!boolMonitor);
boolMonitor = true;
TEST(boolMonitor);
const int64_t loops = 200000;
int64_t nOps = loops;
Thread1 waiter(nOps);
TEST(waiter.start());
while (nOps--)
{
monitor = nOps;
}
const float time = clock.getTimef();
TEST(waiter.join());
std::cout << 2 * loops / time << " ops/ms" << std::endl;
}
{
public:
explicit Thread2(size_t loops)
: innerLoops(0)
, _outerLoops(loops)
{
}
virtual ~Thread2() {}
virtual void run()
{
size_t ops = 0;
for (size_t k = 0; k != 2; ++k)
{
for (size_t i = 0; i != _outerLoops; ++i)
{
const int64_t loops = innerLoops.waitNE(0);
innerLoops = 0;
for (int64_t j = 0; j != loops; ++j)
{
if (innerLoops > 0)
abort();
++monitor;
}
ops += loops * 2 + 2;
}
}
for (size_t k = 0; k != 2; ++k)
{
for (size_t i = 0; i != _outerLoops; ++i)
{
const int64_t loops = innerLoops.
waitNE(0);
innerLoops = 0;
for (int64_t j = 0; j != loops; ++j)
{
if (innerLoops > 0)
abort();
--monitor;
}
ops += loops * 2 + 2;
}
}
std::cout << ops / time << " ops/ms" << std::endl;
}
private:
size_t _outerLoops;
};
void testMonitorComparisons()
{
boolMonitor = true;
const int64_t loops = 1000;
Thread2 waiter(loops);
TEST(waiter.start());
for (int64_t i = 0; i != loops; ++i)
{
monitor = 0;
waiter.innerLoops = i + 1;
TEST(monitor.
waitGE(i + 1) >= i + 1);
TEST(monitor >= i + 1);
}
for (int64_t i = 0; i != loops; ++i)
{
monitor = 0;
waiter.innerLoops = i + 1;
TEST(monitor > i);
}
for (int64_t i = 0; i != loops; ++i)
{
monitor = i + 1;
waiter.innerLoops = i + 1;
TEST(monitor <= 0);
}
for (int64_t i = 0; i != loops; ++i)
{
monitor = i + 1;
waiter.innerLoops = i + 1;
TEST(monitor < 1);
}
TEST(waiter.join());
}
void testTimedMonitorComparisons()
{
boolMonitor = true;
const size_t loops = 1000;
Thread2 waiter(loops);
TEST(waiter.start());
const uint32_t timeout = 1;
for (size_t i = 0; i != loops; ++i)
{
monitor = 0;
waiter.innerLoops = i + 1;
;
TEST(monitor >= i + 1);
}
for (size_t i = 0; i != loops; ++i)
{
monitor = 0;
waiter.innerLoops = i + 1;
;
TEST(monitor > i);
}
for (size_t i = 0; i != loops; ++i)
{
monitor = i + 1;
waiter.innerLoops = i + 1;
;
TEST(monitor <= 0);
}
for (size_t i = 0; i != loops; ++i)
{
monitor = i + 1;
waiter.innerLoops = i + 1;
;
TEST(monitor < 1);
}
TEST(waiter.join());
}
int main(int, char**)
{
testSimpleMonitor();
testMonitorComparisons();
testTimedMonitorComparisons();
return EXIT_SUCCESS;
}