Last active
January 21, 2017 10:53
-
-
Save momchil-velikov/8a366357c11f25bf6a4c to your computer and use it in GitHub Desktop.
Delayed function call facility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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