9 #include <boost/test/unit_test.hpp> 18 static
void microTask(
CScheduler& s,
std::mutex& mutex,
int& counter,
int delta,
std::chrono::steady_clock::time_point rescheduleTime)
21 std::lock_guard<std::mutex> lock(mutex);
24 auto noTime = std::chrono::steady_clock::time_point::min();
25 if (rescheduleTime != noTime) {
27 s.schedule(f, rescheduleTime);
45 std::mutex counterMutex[10];
46 int counter[10] = { 0 };
49 auto randomMsec = [](
FastRandomContext& rc) ->
int {
return -11 + (int)rc.randrange(1012); };
50 auto randomDelta = [](
FastRandomContext& rc) ->
int {
return -1000 + (int)rc.randrange(2001); };
52 auto start = std::chrono::steady_clock::now();
54 std::chrono::steady_clock::time_point first, last;
58 for (
int i = 0; i < 100; ++i) {
59 auto t = now + std::chrono::microseconds(randomMsec(rng));
60 auto tReschedule = now + std::chrono::microseconds(500 + randomMsec(rng));
61 int whichCounter = zeroToNine(rng);
63 std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]),
64 randomDelta(rng), tReschedule);
73 std::vector<std::thread> microThreads;
74 microThreads.reserve(10);
75 for (
int i = 0; i < 5; i++)
79 now = std::chrono::steady_clock::now();
82 for (
int i = 0; i < 5; i++)
84 for (
int i = 0; i < 100; i++) {
85 auto t = now + std::chrono::microseconds(randomMsec(rng));
86 auto tReschedule = now + std::chrono::microseconds(500 + randomMsec(rng));
87 int whichCounter = zeroToNine(rng);
89 std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]),
90 randomDelta(rng), tReschedule);
97 for (
auto& thread: microThreads) {
98 if (thread.joinable()) thread.join();
102 for (
int i = 0; i < 10; i++) {
104 counterSum += counter[i];
111 std::condition_variable condvar;
115 const auto no_wait = [&](
const std::chrono::seconds& d) {
116 return condvar.wait_until(lock, std::chrono::steady_clock::now() - d);
119 BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::seconds{1}));
120 BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::minutes{1}));
121 BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{1}));
122 BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{10}));
123 BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{100}));
124 BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::hours{1000}));
139 std::vector<std::thread> threads;
141 for (
int i = 0; i < 5; ++i) {
142 threads.emplace_back([&] { scheduler.
serviceQueue(); });
152 for (
int i = 0; i < 100; ++i) {
153 queue1.
insert([i, &counter1]() {
154 bool expectation = i == counter1++;
158 queue2.
insert([i, &counter2]() {
159 bool expectation = i == counter2++;
166 for (
auto& thread: threads) {
167 if (thread.joinable()) thread.join();
188 std::chrono::steady_clock::time_point first, last;
192 std::thread scheduler_thread([&]() { scheduler.
serviceQueue(); });
198 scheduler.
scheduleFromNow([&scheduler] { scheduler.
stop(); }, std::chrono::milliseconds{1});
199 scheduler_thread.join();
209 auto now = std::chrono::steady_clock::now();
210 int delta = std::chrono::duration_cast<std::chrono::seconds>(first - now).
count();
static void microTask(CScheduler &s, std::mutex &mutex, int &counter, int delta, std::chrono::steady_clock::time_point rescheduleTime)
void insert(std::function< void()> func) override EXCLUSIVE_LOCKS_REQUIRED(!m_callbacks_mutex)
Add a callback to be executed.
std::function< void()> Function
size_t getQueueInfo(std::chrono::steady_clock::time_point &first, std::chrono::steady_clock::time_point &last) const EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Returns number of tasks waiting to be serviced, and first and last task times.
void stop() EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Tell any threads running serviceQueue to stop as soon as the current task is done.
void StopWhenDrained() EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Tell any threads running serviceQueue to stop when there is no work left to be done.
Class used by CScheduler clients which may schedule multiple jobs which are required to be run serial...
void MockForward(std::chrono::seconds delta_seconds) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Mock the scheduler to fast forward in time.
void serviceQueue() EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Services the queue 'forever'.
BOOST_AUTO_TEST_SUITE_END()
#define WAIT_LOCK(cs, name)
void scheduleFromNow(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Call f once after the delta has passed.
void UninterruptibleSleep(const std::chrono::microseconds &n)
#define BOOST_CHECK_EQUAL(v1, v2)
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
BOOST_AUTO_TEST_SUITE(cuckoocache_tests)
Test Suite for CuckooCache.
void schedule(Function f, std::chrono::steady_clock::time_point t) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Call func at/after time t.
Simple class for background tasks that should be run periodically or once "after a while"...
BOOST_AUTO_TEST_CASE(manythreads)
#define BOOST_CHECK(expr)