API Reference
This page provides a compact reference for the public Vix Async API.
For most application code, include:
#include <vix/async.hpp>The module is divided into two main public namespaces:
vix::async::core
vix::async::netVersion information lives directly in:
vix::asyncTypes under a detail namespace are implementation details and should not be used as application API.
Core namespace
Most runtime types live in:
namespace vix::async::coreCommon application code can use:
using namespace vix::async::core;The main core API consists of:
task<T>
scheduler
io_context
cancel_source
cancel_token
cancel_registration
timer
thread_pool
signal_set
spawn_detached()
when_all()
when_any()
errctask<T>
template <typename T>
class task;task<T> represents a lazy coroutine computation that eventually produces T or throws an exception.
T must not be a reference type.
Use a wrapper such as:
std::reference_wrapper<T>when reference semantics are required.
Construction
task() noexcept;Tasks returned from coroutine functions are constructed by the coroutine machinery.
Application code normally does not construct a task from a coroutine handle directly.
Ownership
task<T> is move-only:
task(task&&) noexcept;
task& operator=(task&&) noexcept;
task(const task&) = delete;
task& operator=(const task&) = delete;State
bool valid() const noexcept;
explicit operator bool() const noexcept;Awaiting
auto operator co_await() & noexcept;
auto operator co_await() && noexcept;The task begins when awaited.
For task<T>, co_await produces T.
For task<void>, it produces no value.
Captured exceptions are rethrown at the await boundary.
Coroutine handle
handle_type handle() const noexcept;
handle_type release() noexcept;These operations expose low-level coroutine ownership.
Most application code does not need them.
Explicit start
void start(scheduler& sched) && noexcept;start():
- posts the coroutine to the scheduler
- marks the task detached
- releases ownership from the
taskobject
Typical root-task use:
std::move(run(ctx)).start(
ctx.get_scheduler()
);See Tasks.
task<void>
template <>
class task<void>;task<void> follows the same ownership, suspension, exception, and start rules as task<T>, but has no return value.
Typical form:
task<void> work()
{
co_return;
}scheduler
class scheduler;The scheduler executes ready coroutine handles and callbacks on the thread running run().
It is non-copyable.
Post a callback
template <typename Fn>
void post(Fn&& fn);Queues an ordinary callable.
Post a coroutine
void post(
std::coroutine_handle<> handle
) noexcept;Explicit fast-path alias:
void post_handle(
std::coroutine_handle<> handle
) noexcept;Schedule the current coroutine
schedule_awaitable schedule() noexcept;Usage:
co_await sched.schedule();The coroutine is posted to the scheduler and later resumes on the scheduler's run() thread.
Run
void run();Runs the scheduler event loop on the calling thread.
Coroutine handles are processed before generic callback work.
Stop
void stop() noexcept;Requests stop.
Already queued work is drained before run() exits.
Reset
void reset() noexcept;Clears the scheduler stop request.
It must not be used while run() is active.
State
bool is_running() const noexcept;
bool stop_requested() const noexcept;See Scheduler.
io_context
class io_context;io_context owns the core scheduler and lazily creates Async services.
It is non-copyable.
Scheduler
scheduler& get_scheduler() noexcept;
const scheduler&
get_scheduler() const noexcept;Post callbacks
template <typename Fn>
void post(Fn&& fn);Post coroutine handles
void post(
std::coroutine_handle<> handle
) noexcept;
void post_handle(
std::coroutine_handle<> handle
) noexcept;Run
void run();Equivalent to driving the context scheduler.
Stop
void stop() noexcept;Requests scheduler stop.
Running state
bool is_running() const noexcept;CPU service
thread_pool& cpu_pool();Created lazily.
Throws std::runtime_error when accessed after context shutdown.
Timer service
timer& timers();Created lazily.
Throws std::runtime_error when accessed after context shutdown.
Signal service
signal_set& signals();Created lazily.
Throws std::runtime_error when accessed after context shutdown.
Networking
Public networking objects should normally be created through:
net::make_tcp_stream(ctx);
net::make_tcp_listener(ctx);
net::make_udp_socket(ctx);
net::make_dns_resolver(ctx);The context also exposes its backend internally for integration, but application code should not depend on vix::async::net::detail.
Shutdown
void shutdown() noexcept;Shuts down lazily created services while the scheduler can still accept their final completions, then stops the scheduler.
shutdown() is idempotent.
The destructor performs shutdown automatically.
See io_context and Lifecycle and Shutdown.
Cancellation
Cancellation is cooperative.
The primary public types are:
cancel_source
cancel_token
cancel_registrationcancel_source
class cancel_source;Create a cancellation state:
cancel_source source;Get a token:
cancel_token token() const noexcept;Request cancellation:
void request_cancel() noexcept;Inspect state:
bool is_cancelled() const noexcept;cancel_token
class cancel_token;An empty token is valid and represents no cancellation source.
cancel_token();Inspect whether cancellation is available:
bool can_cancel() const noexcept;Inspect cancellation state:
bool is_cancelled() const noexcept;Register a callback:
cancel_registration on_cancel(
std::function<void()> fn
) const;If cancellation was already requested, the callback runs during on_cancel().
cancel_registration
class cancel_registration;The registration is move-only.
Remove the callback registration:
void reset() noexcept;Inspect its state:
bool active() const noexcept;Destroying the registration also removes an active callback registration.
Cancellation error
std::error_code
cancelled_ec() noexcept;Equivalent to:
make_error_code(
errc::canceled
);See Cancellation.
timer
class timer;The timer service uses:
using clock =
std::chrono::steady_clock;
using time_point =
clock::time_point;
using duration =
clock::duration;Delayed callback
template <typename Fn>
void after(
duration delay,
Fn&& fn,
cancel_token token = {}
);Schedules a callback for later execution through the context scheduler.
Coroutine sleep
task<void> sleep_for(
duration delay,
cancel_token token = {}
);Suspends the coroutine until:
- the delay expires
- cancellation occurs
- the timer service stops
Stop
void stop() noexcept;State
bool stopped() const noexcept;See Timers.
thread_pool
class thread_pool;The pool executes synchronous callables on worker threads.
Construction
explicit thread_pool(
io_context& ctx,
std::size_t threads =
std::thread::hardware_concurrency()
);A requested size of zero still produces at least one worker.
Most applications use:
ctx.cpu_pool();instead of constructing a separate pool.
Fire-and-forget work
bool post(
std::function<void()> fn
);Returns true if accepted.
Returns false if the job cannot be accepted.
Submit and await
template <typename Fn>
auto submit(
Fn&& fn,
cancel_token token = {}
)
-> task<
std::invoke_result_t<
std::decay_t<Fn>&
>
>;The callable runs on a worker.
Its result or exception returns through the awaiting task.
Cancellation is checked before execution begins.
Stop
void stop() noexcept;Rejects new work while accepted work drains.
Shutdown
void shutdown() noexcept;Stops the pool and joins its worker threads.
The operation is idempotent.
State
bool stopped() const noexcept;
std::size_t size() const noexcept;See Thread Pool and CPU Offloading.
signal_set
class signal_set;Add a signal
void add(int signal);Remove a signal
void remove(int signal);Await the next signal
task<int> async_wait(
cancel_token token = {}
);Returns the received signal number.
Only one active waiter is supported at a time.
Observe signals with a callback
void on_signal(
std::function<void(int)> fn
);The callback is posted through the context scheduler.
Stop
void stop() noexcept;Stops signal watching and releases an active waiter.
See Signals.
Detached tasks
Use:
void spawn_detached(
io_context& ctx,
task<void> task
);to start a task<void> without retaining an awaitable result.
Example:
spawn_detached(
ctx,
background(ctx)
);The detached coroutine self-destroys when complete.
Exceptions escaping the detached task are consumed at the detached boundary.
when_all
template <typename... Ts>
task<
std::tuple<
std::conditional_t<
std::is_void_v<Ts>,
std::monostate,
Ts
>...
>
>
when_all(
scheduler& sched,
task<Ts>... tasks
);when_all:
- starts all supplied tasks
- waits for every task
- preserves argument order in the result tuple
- maps
task<void>tostd::monostate - accepts zero tasks
- rethrows the first captured exception after all tasks finish
Example:
auto results = co_await when_all(
ctx.get_scheduler(),
first(),
second()
);when_any
The logical public result type is:
template <typename... Ts>
task<
std::pair<
std::size_t,
std::tuple<
std::optional<
result_or_monostate<Ts>
>...
>
>
>
when_any(
scheduler& sched,
task<Ts>... tasks
);The actual implementation uses an internal storage alias for those optional result slots.
For a non-void T:
std::optional<std::decay_t<T>>For void:
std::optional<std::monostate>when_any:
- requires at least one task
- starts every supplied task
- returns the zero-based index of the first completed task
- populates only the winning result slot
- returns on success or exception
- does not automatically cancel losing tasks
Example:
auto [index, results] = co_await when_any(
ctx.get_scheduler(),
first(),
second()
);Errors
Async runtime errors use:
enum class errc : std::uint8_t
{
ok = 0,
invalid_argument,
not_ready,
timeout,
canceled,
closed,
overflow,
stopped,
queue_full,
rejected,
not_supported
};Create an error code with:
std::error_code make_error_code(
errc error
) noexcept;Access the category with:
const std::error_category&
category() noexcept;The category name is:
asyncAsync operations commonly report runtime conditions through std::system_error.
Networking also preserves underlying operating-system and Asio error codes.
See Errors.
Networking
Public network types live in:
namespace vix::async::netThe public abstractions are:
tcp_endpoint
tcp_stream
tcp_listener
udp_endpoint
udp_datagram
udp_socket
resolved_address
dns_resolverNetwork objects are created through factory functions associated with a core io_context.
tcp_endpoint
struct tcp_endpoint
{
std::string host;
std::uint16_t port{0};
};The port is represented in host byte order.
tcp_stream
class tcp_stream;Connect
virtual core::task<void>
async_connect(
const tcp_endpoint& endpoint,
core::cancel_token token = {}
) = 0;Read
virtual core::task<std::size_t>
async_read(
std::span<std::byte> buffer,
core::cancel_token token = {}
) = 0;Reads up to buffer.size() bytes.
Write
virtual core::task<std::size_t>
async_write(
std::span<const std::byte> buffer,
core::cancel_token token = {}
) = 0;Returns the number of bytes written by that operation.
Close
virtual void close() noexcept = 0;State
virtual bool is_open() const noexcept = 0;Native handle
virtual int native_handle();Implementations that do not expose a native socket handle may throw std::runtime_error.
Factory
std::unique_ptr<tcp_stream>
make_tcp_stream(
core::io_context& ctx
);See TCP.
tcp_listener
class tcp_listener;Listen
virtual core::task<void>
async_listen(
const tcp_endpoint& endpoint,
int backlog = 128
) = 0;Accept
virtual core::task<
std::unique_ptr<tcp_stream>
>
async_accept(
core::cancel_token token = {}
) = 0;Close
virtual void close() noexcept = 0;State
virtual bool is_open() const noexcept = 0;Factory
std::unique_ptr<tcp_listener>
make_tcp_listener(
core::io_context& ctx
);See TCP.
udp_endpoint
struct udp_endpoint
{
std::string host;
std::uint16_t port{0};
};udp_datagram
struct udp_datagram
{
udp_endpoint from;
std::size_t bytes{0};
};from identifies the sender.
bytes is the number of bytes written into the receive buffer.
udp_socket
class udp_socket;Bind
virtual core::task<void>
async_bind(
const udp_endpoint& endpoint
) = 0;Send
virtual core::task<std::size_t>
async_send_to(
std::span<const std::byte> buffer,
const udp_endpoint& destination,
core::cancel_token token = {}
) = 0;Receive
virtual core::task<udp_datagram>
async_recv_from(
std::span<std::byte> buffer,
core::cancel_token token = {}
) = 0;Close
virtual void close() noexcept = 0;State
virtual bool is_open() const noexcept = 0;Factory
std::unique_ptr<udp_socket>
make_udp_socket(
core::io_context& ctx
);See UDP.
resolved_address
struct resolved_address
{
std::string ip;
std::uint16_t port{0};
};dns_resolver
class dns_resolver;Resolve a hostname and port:
virtual core::task<
std::vector<resolved_address>
>
async_resolve(
std::string host,
std::uint16_t port,
core::cancel_token token = {}
) = 0;Factory:
std::unique_ptr<dns_resolver>
make_dns_resolver(
core::io_context& ctx
);See DNS.
Version
Version constants live in:
namespace vix::asyncThe current module version is:
1.2.1Available constants:
inline constexpr int version_major = 1;
inline constexpr int version_minor = 2;
inline constexpr int version_patch = 1;
inline constexpr const char*
version_prerelease = "";
inline constexpr const char*
version_metadata = "";
inline constexpr const char*
version_string = "1.2.1";
inline constexpr int abi_version = 1;For example:
#include <vix/async.hpp>
#include <vix/print.hpp>
int main()
{
vix::print(
"Vix Async",
vix::async::version_string
);
return 0;
}Public API map
The complete application-facing model is:
vix::async
│
├── version
│
├── core
│ ├── task<T>
│ ├── scheduler
│ ├── io_context
│ │
│ ├── cancellation
│ │ ├── cancel_source
│ │ ├── cancel_token
│ │ └── cancel_registration
│ │
│ ├── timer
│ ├── thread_pool
│ ├── signal_set
│ │
│ ├── spawn_detached
│ ├── when_all
│ ├── when_any
│ │
│ └── errors
│ └── errc
│
└── net
├── TCP
│ ├── tcp_endpoint
│ ├── tcp_stream
│ └── tcp_listener
│
├── UDP
│ ├── udp_endpoint
│ ├── udp_datagram
│ └── udp_socket
│
└── DNS
├── resolved_address
└── dns_resolverFor behavior, execution rules, lifetime, and examples, use the dedicated pages rather than treating this reference as the complete programming guide.
Start with: