Skip to content

Instantly share code, notes, and snippets.

@DieTime
Created August 1, 2022 16:38
Show Gist options
  • Save DieTime/61d4906cad53cad01253f63f89d58145 to your computer and use it in GitHub Desktop.
Save DieTime/61d4906cad53cad01253f63f89d58145 to your computer and use it in GitHub Desktop.
Simple async C++
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
#include <queue>
namespace Async {
struct Task
{
std::function<void()> callback;
std::chrono::time_point<std::chrono::steady_clock> time;
Task(std::chrono::seconds after, std::function<void()> callback)
: callback(std::move(callback))
{
time = std::chrono::steady_clock::now() + after;
}
explicit Task(std::function<void()> callback)
: callback(std::move(callback))
{}
};
struct TaskComparator
{
bool operator()(const Task &a, const Task &b) { return a.time >= b.time; }
};
class Scheduler
{
public:
explicit Scheduler() = default;
~Scheduler() = default;
Scheduler(Scheduler const &) = delete;
Scheduler(Scheduler &&) = delete;
Scheduler &operator=(Scheduler const &) = delete;
Scheduler &operator=(Scheduler &&) = delete;
template<typename Callback>
static void Now(Callback callback)
{
auto instance = Instance();
instance->m_queue.emplace(callback);
}
template<typename Callback>
static void Later(Callback callback, std::chrono::seconds seconds)
{
auto instance = Instance();
instance->m_waiting.emplace(seconds, callback);
}
template<typename Callback>
static void Repeat(Callback callback, std::chrono::seconds seconds)
{
auto repeater = [callback, seconds]() {
callback();
Scheduler::Repeat(callback, seconds);
};
Scheduler::Later(repeater, seconds);
}
static void Run()
{
while (true) {
ProcessWaiting();
ProcessQueued();
}
}
private:
std::queue<Task> m_queue;
std::priority_queue<Task, std::vector<Task>, TaskComparator> m_waiting;
static std::shared_ptr<Scheduler> m_instance;
static std::shared_ptr<Scheduler> Instance()
{
if (!m_instance)
m_instance = std::make_shared<Scheduler>();
return m_instance;
}
static void ProcessWaiting()
{
auto instance = Instance();
while (!instance->m_waiting.empty()) {
auto t = instance->m_waiting.top();
if (std::chrono::steady_clock::now() < t.time)
break;
t.callback();
instance->m_waiting.pop();
}
}
static void ProcessQueued()
{
auto instance = Instance();
while (!instance->m_queue.empty()) {
Task t = instance->m_queue.front();
t.callback();
instance->m_queue.pop();
}
}
};
std::shared_ptr<Scheduler> Scheduler::m_instance = nullptr;
} /* namespace Async */
void f0()
{
std::cout << "0" << std::endl;
}
void f1()
{
std::cout << "1" << std::endl;
}
void f3()
{
std::cout << "3" << std::endl;
}
void f2()
{
std::cout << "2" << std::endl;
Async::Scheduler::Now(f3);
}
int main()
{
Async::Scheduler::Later(f0, std::chrono::seconds(1));
Async::Scheduler::Now(f1);
Async::Scheduler::Repeat(f2, std::chrono::seconds(2));
Async::Scheduler::Run();
/*
* 1 <- now
* 0 <- after 1 sec
* 2 <- after 2 sec
* 3 <- after 2 sec
* 2 <- after 4 sec
* 3 <- after 4 sec
* ...
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment