scheduler
Minimal single-thread scheduler for async tasks and coroutine resumption.
Overview
scheduler is the core execution engine of the Vix async runtime.
It provides:
- A thread-safe FIFO job queue
- An event loop (
run()) - Posting of:
- Generic callables
- Coroutine continuations
- An awaitable (
schedule()) to hop onto the scheduler thread
It is intentionally:
- Small
- Deterministic
- Single-threaded (run() executes on the calling thread)
- Designed to be embedded inside
io_context
Basic Usage
cpp
#include <vix/async/core/scheduler.hpp>
using namespace vix::async::core;
int main()
{
scheduler sched;
sched.post([] {
std::cout << "Hello from scheduler\n";
});
sched.run(); // blocks
}Posting Work
1. Posting a Callable
cpp
sched.post([] {
do_something();
});The callable is:
- Stored in a type-erased job
- Enqueued
- Executed when
run()processes it
2. Posting a Coroutine Handle
cpp
std::coroutine_handle<> h = ...;
sched.post(h);The scheduler wraps the handle into a job that resumes the coroutine.
Awaitable Scheduling
The scheduler provides:
cpp
co_await sched.schedule();What it does
- Always suspends
- Posts the continuation to the scheduler queue
- Resumes execution on the scheduler thread
Example:
cpp
task<void> my_task(scheduler& sched)
{
co_await sched.schedule();
std::cout << "Now running inside scheduler thread\n";
}Event Loop
run()
cpp
sched.run();Behavior:
- Blocks the calling thread
- Waits on condition_variable
- Processes jobs in FIFO order
- Exits when:
stop()is requested- Queue is empty and stop flag observed
stop()
cpp
sched.stop();- Sets stop flag
- Wakes all waiters
- Allows
run()to exit cleanly
Introspection
cpp
bool running = sched.is_running();
std::size_t pending = sched.pending();is_running()→ whether run() loop is activepending()→ number of queued jobs
Internal Design
Job Queue
Jobs are stored as:
cpp
std::deque<job>Each job contains:
- A small type-erased callable holder
- Move-only semantics
- Virtual dispatch through a lightweight polymorphic base
This avoids std::function overhead while remaining generic.
Thread Safety
Protected by:
std::mutexstd::condition_variable
Safe for:
- Multiple producers calling
post() - Single consumer running
run()
Design Principles
scheduler is intentionally:
- Minimal
- Predictable
- Not a thread pool
- Not a work-stealing system
- Not multi-threaded
Higher-level concurrency (CPU pools, networking, timers) is built on top of this primitive.
Typical Role in Vix
scheduler is embedded inside:
cpp
io_contextThe io_context:
- Owns a scheduler
- Exposes higher-level async services
- Coordinates timers, signals, networking
Summary
scheduler is the lowest-level execution primitive of the Vix async core:
- FIFO task execution
- Coroutine resumption
- Deterministic single-thread loop
- Foundation for the entire runtime
It is small by design — everything else builds on top of it.