Created
August 1, 2022 16:38
-
-
Save DieTime/61d4906cad53cad01253f63f89d58145 to your computer and use it in GitHub Desktop.
Simple async C++
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
#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