Changeset View
Changeset View
Standalone View
Standalone View
src/scheduler.h
Show All 18 Lines | |||||
// | // | ||||
// Simple class for background tasks that should be run periodically or once | // Simple class for background tasks that should be run periodically or once | ||||
// "after a while" | // "after a while" | ||||
// | // | ||||
// Usage: | // Usage: | ||||
// | // | ||||
// CScheduler* s = new CScheduler(); | // CScheduler* s = new CScheduler(); | ||||
// s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { } | // // Assuming a: void doSomething() { } | ||||
// s->scheduleFromNow(std::bind(Class::func, this, argument), 3); | // s->scheduleFromNow(doSomething, std::chrono::milliseconds{11}); | ||||
// s->scheduleFromNow([=] { this->func(argument); }, | |||||
// std::chrono::milliseconds{3}); | |||||
// boost::thread* t = new boost::thread(std::bind(CScheduler::serviceQueue, s)); | // boost::thread *t = new boost::thread(std::bind(CScheduler::serviceQueue, s)); | ||||
// | // | ||||
// ... then at program shutdown, make sure to call stop() to clean up the | // ... then at program shutdown, make sure to call stop() to clean up the | ||||
// thread(s) running serviceQueue: | // thread(s) running serviceQueue: | ||||
// s->stop(); | // s->stop(); | ||||
// t->join(); | // t->join(); | ||||
// delete t; | // delete t; | ||||
// delete s; // Must be done after thread is interrupted/joined. | // delete s; // Must be done after thread is interrupted/joined. | ||||
// | // | ||||
class CScheduler { | class CScheduler { | ||||
public: | public: | ||||
CScheduler(); | CScheduler(); | ||||
~CScheduler(); | ~CScheduler(); | ||||
typedef std::function<void()> Function; | typedef std::function<void()> Function; | ||||
typedef std::function<bool()> Predicate; | typedef std::function<bool()> Predicate; | ||||
// Call func at/after time t | // Call func at/after time t | ||||
void schedule(Function f, std::chrono::system_clock::time_point t); | void schedule(Function f, std::chrono::system_clock::time_point t); | ||||
// Convenience method: call f once deltaMilliSeconds from now | /** Call f once after the delta has passed */ | ||||
void scheduleFromNow(Function f, int64_t deltaMilliSeconds); | void scheduleFromNow(Function f, std::chrono::milliseconds delta) { | ||||
schedule(std::move(f), std::chrono::system_clock::now() + delta); | |||||
} | |||||
// Another convenience method: call p approximately every deltaMilliSeconds | /** | ||||
// forever, starting deltaMilliSeconds from now untill p returns false. To | * Repeat p until it return false. First run is after delta has passed once. | ||||
// be more precise: every time p is finished, it is rescheduled to run | * | ||||
// deltaMilliSeconds later. If you need more accurate scheduling, don't use | * The timing is not exact: Every time p is finished, it is rescheduled to | ||||
// this method. | * run again after delta. If you need more accurate scheduling, don't use | ||||
void scheduleEvery(Predicate p, int64_t deltaMilliSeconds); | * this method. | ||||
*/ | |||||
void scheduleEvery(Predicate p, std::chrono::milliseconds delta); | |||||
/** | /** | ||||
* Mock the scheduler to fast forward in time. | * Mock the scheduler to fast forward in time. | ||||
* Iterates through items on taskQueue and reschedules them | * Iterates through items on taskQueue and reschedules them | ||||
* to be delta_seconds sooner. | * to be delta_seconds sooner. | ||||
*/ | */ | ||||
void MockForward(std::chrono::seconds delta_seconds); | void MockForward(std::chrono::seconds delta_seconds); | ||||
Show All 16 Lines | public: | ||||
// Returns true if there are threads actively running in serviceQueue() | // Returns true if there are threads actively running in serviceQueue() | ||||
bool AreThreadsServicingQueue() const; | bool AreThreadsServicingQueue() const; | ||||
private: | private: | ||||
mutable Mutex newTaskMutex; | mutable Mutex newTaskMutex; | ||||
std::condition_variable newTaskScheduled; | std::condition_variable newTaskScheduled; | ||||
std::multimap<std::chrono::system_clock::time_point, Function> | std::multimap<std::chrono::system_clock::time_point, Function> | ||||
taskQueue GUARDED_BY(newTaskMutex); | taskQueue GUARDED_BY(newTaskMutex); | ||||
int nThreadsServicingQueue GUARDED_BY(newTaskMutex); | int nThreadsServicingQueue GUARDED_BY(newTaskMutex){0}; | ||||
bool stopRequested GUARDED_BY(newTaskMutex); | bool stopRequested GUARDED_BY(newTaskMutex){false}; | ||||
bool stopWhenEmpty GUARDED_BY(newTaskMutex); | bool stopWhenEmpty GUARDED_BY(newTaskMutex){false}; | ||||
bool shouldStop() const EXCLUSIVE_LOCKS_REQUIRED(newTaskMutex) { | bool shouldStop() const EXCLUSIVE_LOCKS_REQUIRED(newTaskMutex) { | ||||
return stopRequested || (stopWhenEmpty && taskQueue.empty()); | return stopRequested || (stopWhenEmpty && taskQueue.empty()); | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
* Class used by CScheduler clients which may schedule multiple jobs | * Class used by CScheduler clients which may schedule multiple jobs | ||||
* which are required to be run serially. Jobs may not be run on the | * which are required to be run serially. Jobs may not be run on the | ||||
Show All 40 Lines |