Skip to content

Instantly share code, notes, and snippets.

@momchil-velikov
Last active January 21, 2017 10:53
Show Gist options
  • Save momchil-velikov/8a366357c11f25bf6a4c to your computer and use it in GitHub Desktop.
Save momchil-velikov/8a366357c11f25bf6a4c to your computer and use it in GitHub Desktop.
Delayed function call facility
// c++/clang++ -pthread --std=c++11 delay-call.cc -o delay-call
#include <iostream>
#include <functional>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <queue>
#include <ctime>
namespace chrono = std::chrono;
using steady_clock = chrono::steady_clock;
using time_point = chrono::time_point<steady_clock>;
using function = std::function<void()>;
using lock_guard = std::unique_lock<std::mutex>;
namespace {
struct call {
call(const time_point &tm, const function &fn) : tm(tm), fn(fn) {}
time_point tm;
function fn;
};
};
namespace std {
template<> struct less<call> {
bool operator()(const call &a, const call &b) const {
return a.tm >= b.tm;
}
};
}
class DelayCaller {
public:
DelayCaller() : thr(&DelayCaller::runner, this) {}
template<typename T> void schedule(chrono::milliseconds ms, T &&fn) {
lock_guard _(lock);
queue.emplace(steady_clock::now() + ms, fn);
cond.notify_one();
}
void stop() {
{
lock_guard _(lock);
stop_request = true;
cond.notify_one();
}
thr.join();
}
private:
bool stop_request = false;
std::thread thr;
std::priority_queue<call> queue;
std::mutex lock;
std::condition_variable cond;
void runner();
};
void DelayCaller::runner() {
while(true) {
lock_guard guard(lock);
if (stop_request)
break;
while (!queue.empty() && queue.top().tm < steady_clock::now()) {
call c = queue.top();
queue.pop();
c.fn();
}
if (queue.empty()) {
cond.wait(guard);
} else {
cond.wait_until(guard, queue.top().tm);
}
}
}
int main() {
DelayCaller c;
c.schedule(chrono::milliseconds(1000), []{ std::cout << "1000" << std::endl; });
c.schedule(chrono::milliseconds(2000), []{ std::cout << "2000" << std::endl; });
c.schedule(chrono::milliseconds(1500), []{ std::cout << "1500" << std::endl; });
c.schedule(chrono::milliseconds(100), []{ std::cout << "100" << std::endl; });
std::this_thread::sleep_for(chrono::seconds(10));
c.stop();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment