This page is a compact reference for the public Vix Async API.
Use it when you want to quickly find the main types, functions, and operations exposed by vix::async.
#include <vix/async.hpp>
#include <vix/print.hpp>Core async APIs live in:
vix::async::core
Networking APIs live in:
vix::async::net
| Component | Purpose |
|---|---|
io_context |
Central async runtime context. |
scheduler |
Runs callbacks and resumes coroutines. |
task<T> |
Coroutine task producing a value. |
task<void> |
Coroutine task with no returned value. |
cancel_source |
Owns cancellation state. |
cancel_token |
Observes cancellation state. |
timer |
Delayed callbacks and coroutine sleeps. |
thread_pool |
Background worker pool for CPU or blocking work. |
signal_set |
Async signal watching. |
when_all |
Waits for multiple tasks to complete. |
when_any |
Waits for the first task to complete. |
dns_resolver |
Async hostname resolution. |
tcp_stream |
Connected TCP stream. |
tcp_listener |
TCP server listener. |
udp_socket |
UDP datagram socket. |
io_context is the central runtime object.
vix::async::core::io_context ctx;It owns the scheduler and async services.
Posts a callback to the scheduler.
ctx.post([&ctx]()
{
vix::print("hello");
ctx.stop();
});Runs the scheduler loop. Blocks until the context is stopped.
ctx.run();Requests the scheduler loop to stop.
ctx.stop();Checks whether the scheduler is running.
vix::print("running =", ctx.is_running() ? "yes" : "no");Returns the internal scheduler.
auto &sched = ctx.get_scheduler();Use it when starting tasks.
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());Returns the CPU thread pool.
auto &pool = ctx.cpu_pool();Use it to run blocking or CPU-heavy work.
Returns the timer service.
auto &timers = ctx.timers();Use it for delayed callbacks and coroutine sleeps.
Returns the signal service.
auto &signals = ctx.signals();Use it for async signal handling.
Returns the internal networking backend.
ctx.net();Most user code should prefer the higher-level networking factories:
vix::async::net::make_dns_resolver(ctx);
vix::async::net::make_tcp_stream(ctx);
vix::async::net::make_tcp_listener(ctx);
vix::async::net::make_udp_socket(ctx);Stops the scheduler and releases services.
ctx.shutdown();The destructor also shuts down the context.
scheduler runs callbacks and coroutine continuations.
Most application code uses it through io_context.
auto &sched = ctx.get_scheduler();Posts a callable.
sched.post([]()
{
vix::print("callback");
});Posts a coroutine handle. Most user code does not call this directly.
sched.post_handle(handle);Creates an awaitable that resumes the coroutine on the scheduler.
co_await ctx.get_scheduler().schedule();Runs the scheduler loop. In normal applications, prefer ctx.run().
Stops the scheduler. In normal applications, prefer ctx.stop().
task<T> is the main coroutine task type.
Use task<T> when the coroutine returns a value.
vix::async::core::task<int> compute()
{
co_return 42;
}Await it from another task:
const int value = co_await compute();Use task<void> when the coroutine returns no value.
vix::async::core::task<void> work()
{
vix::print("working");
co_return;
}Starts a task on a scheduler. Tasks are lazy — they do not run until awaited or started.
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());Checks whether a task owns a coroutine handle.
if (t.valid())
{
vix::print("valid task");
}Equivalent:
if (t)
{
vix::print("valid task");
}Releases the underlying coroutine handle. Most user code should prefer start.
auto handle = t.release();#include <vix/async.hpp>
#include <vix/print.hpp>
vix::async::core::task<int> compute()
{
co_return 42;
}
vix::async::core::task<void> app(vix::async::core::io_context &ctx)
{
const int value = co_await compute();
vix::print("value =", value);
ctx.stop();
co_return;
}
int main()
{
vix::async::core::io_context ctx;
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
ctx.run();
return 0;
}Vix Async cancellation is cooperative.
Owns the cancellation state.
vix::async::core::cancel_source source;Request cancellation:
source.request_cancel();Check source state:
if (source.is_cancelled())
{
vix::print("cancelled");
}Observes cancellation state.
vix::async::core::cancel_token token = source.token();Check whether the token is connected to a source:
if (token.can_cancel())
{
vix::print("can cancel");
}Check whether cancellation was requested:
if (token.is_cancelled())
{
vix::print("cancel requested");
}Returns the standard async cancellation error code.
const std::error_code ec = vix::async::core::cancelled_ec();
vix::print("message =", ec.message());timer provides delayed callbacks and coroutine sleeps.
Access it through io_context.
ctx.timers()Suspends a coroutine for a duration.
co_await ctx.timers().sleep_for(std::chrono::milliseconds(100));With cancellation:
co_await ctx.timers().sleep_for(
std::chrono::seconds(1),
source.token());Schedules a callback after a duration.
ctx.timers().after(std::chrono::milliseconds(100), []()
{
vix::print("timer fired");
});With cancellation:
ctx.timers().after(
std::chrono::seconds(1),
[]()
{
vix::print("callback");
},
source.token());#include <vix/async.hpp>
#include <vix/print.hpp>
#include <chrono>
using namespace std::chrono_literals;
vix::async::core::task<void> app(vix::async::core::io_context &ctx)
{
vix::print("before sleep");
co_await ctx.timers().sleep_for(100ms);
vix::print("after sleep");
ctx.stop();
co_return;
}
int main()
{
vix::async::core::io_context ctx;
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
ctx.run();
return 0;
}thread_pool runs CPU-heavy or blocking work outside the scheduler thread.
Access it through io_context.
ctx.cpu_pool()Submits a plain callback.
ctx.cpu_pool().submit([]()
{
do_work();
});Submits a callable and awaits the result.
int value = co_await ctx.cpu_pool().submit([]()
{
return 42;
});With cancellation:
int value = co_await ctx.cpu_pool().submit([]()
{
return 42;
}, source.token());#include <vix/async.hpp>
#include <vix/print.hpp>
vix::async::core::task<void> app(vix::async::core::io_context &ctx)
{
int value = co_await ctx.cpu_pool().submit([]()
{
return 21 * 2;
});
vix::print("value =", value);
ctx.stop();
co_return;
}
int main()
{
vix::async::core::io_context ctx;
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
ctx.run();
return 0;
}when_all starts multiple tasks and waits until all of them complete.
auto results = co_await vix::async::core::when_all(
ctx.get_scheduler(),
first(),
second());Results are returned as a tuple.
const auto a = std::get<0>(results);
const auto b = std::get<1>(results);Example:
#include <vix/async.hpp>
#include <vix/print.hpp>
#include <tuple>
vix::async::core::task<int> first()
{
co_return 20;
}
vix::async::core::task<int> second()
{
co_return 22;
}
vix::async::core::task<void> app(vix::async::core::io_context &ctx)
{
auto results = co_await vix::async::core::when_all(
ctx.get_scheduler(),
first(),
second());
vix::print("sum =", std::get<0>(results) + std::get<1>(results));
ctx.stop();
co_return;
}
int main()
{
vix::async::core::io_context ctx;
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
ctx.run();
return 0;
}when_any starts multiple tasks and waits for the first one to complete.
auto result = co_await vix::async::core::when_any(
ctx.get_scheduler(),
fast(),
slow());The result contains:
| Field | Purpose |
|---|---|
result.first |
Index of the first completed task. |
result.second |
Tuple of optional result slots. |
Example:
const std::size_t index = result.first;
auto values = std::move(result.second);signal_set watches system signals.
Access it through io_context.
ctx.signals()Adds a signal to watch.
ctx.signals().add(SIGINT);Removes a watched signal.
ctx.signals().remove(SIGINT);Waits for the next signal.
const int sig = co_await ctx.signals().async_wait();With cancellation:
const int sig = co_await ctx.signals().async_wait(source.token());Registers a callback.
ctx.signals().on_signal([](int sig)
{
vix::print("signal =", sig);
});Stops signal watching.
ctx.signals().stop();#include <vix/async.hpp>
#include <vix/print.hpp>
#include <csignal>
vix::async::core::task<void> app(vix::async::core::io_context &ctx)
{
ctx.signals().add(SIGINT);
vix::print("press Ctrl+C to stop");
const int sig = co_await ctx.signals().async_wait();
vix::print("signal =", sig);
ctx.stop();
co_return;
}
int main()
{
vix::async::core::io_context ctx;
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
ctx.run();
return 0;
}DNS APIs live in vix::async::net.
Represents one resolved endpoint.
| Field | Purpose |
|---|---|
ip |
IP address as text. |
port |
Port number. |
Creates a resolver attached to an io_context.
auto resolver = vix::async::net::make_dns_resolver(ctx);Resolves a hostname and port.
auto addresses = co_await resolver->async_resolve(
"example.com",
80);With cancellation:
auto addresses = co_await resolver->async_resolve(
"example.com",
80,
source.token());TCP APIs live in vix::async::net.
Describes a TCP endpoint.
vix::async::net::tcp_endpoint endpoint{
"127.0.0.1",
8080
};| Field | Purpose |
|---|---|
host |
Hostname or IP address. |
port |
TCP port. |
Represents a connected TCP stream.
| Method | Purpose |
|---|---|
async_connect(endpoint, token) |
Connects to a remote endpoint. |
async_read(buffer, token) |
Reads bytes. |
async_write(buffer, token) |
Writes bytes. |
close() |
Closes the stream. |
is_open() |
Checks open state. |
native_handle() |
Returns native socket handle when supported. |
Creates a TCP stream.
auto stream = vix::async::net::make_tcp_stream(ctx);Connects to a remote endpoint.
co_await stream->async_connect({
"example.com",
80
});With cancellation:
co_await stream->async_connect(endpoint, source.token());Reads bytes into a mutable byte buffer.
std::array<std::byte, 1024> buffer{};
const std::size_t bytes = co_await stream->async_read(
std::span<std::byte>{buffer.data(), buffer.size()});Writes bytes from an immutable byte buffer.
std::string message = "hello";
const std::size_t bytes = co_await stream->async_write(
std::as_bytes(std::span{message}));Represents a listening TCP socket.
| Method | Purpose |
|---|---|
async_listen(endpoint, backlog) |
Starts listening. |
async_accept(token) |
Accepts one connection. |
close() |
Closes the listener. |
is_open() |
Checks open state. |
Creates a TCP listener.
auto listener = vix::async::net::make_tcp_listener(ctx);Starts listening on a local endpoint.
co_await listener->async_listen({
"127.0.0.1",
8080
});Accepts one incoming connection. The returned client is a std::unique_ptr<tcp_stream>.
auto client = co_await listener->async_accept();UDP APIs live in vix::async::net.
Describes a UDP endpoint.
vix::async::net::udp_endpoint endpoint{
"127.0.0.1",
9000
};| Field | Purpose |
|---|---|
host |
Hostname or IP address. |
port |
UDP port. |
Describes a received datagram.
| Field | Purpose |
|---|---|
from |
Sender endpoint. |
bytes |
Number of received bytes. |
Represents a UDP socket.
| Method | Purpose |
|---|---|
async_bind(endpoint) |
Binds to a local endpoint. |
async_send_to(buffer, endpoint, token) |
Sends one datagram. |
async_recv_from(buffer, token) |
Receives one datagram. |
close() |
Closes the socket. |
is_open() |
Checks open state. |
Creates a UDP socket.
auto socket = vix::async::net::make_udp_socket(ctx);Binds the socket to a local endpoint.
co_await socket->async_bind({
"127.0.0.1",
9000
});Sends one datagram.
std::string message = "hello";
const std::size_t bytes = co_await socket->async_send_to(
std::as_bytes(std::span{message}),
{
"127.0.0.1",
9000
});Receives one datagram.
std::array<std::byte, 1024> buffer{};
const auto datagram = co_await socket->async_recv_from(
std::span<std::byte>{buffer.data(), buffer.size()});Async core errors use vix::async::core::errc.
| Error | Meaning |
|---|---|
ok |
No error. |
invalid_argument |
Invalid argument. |
not_ready |
Operation cannot complete yet. |
timeout |
Operation timed out. |
canceled |
Operation was canceled. |
closed |
Resource was closed. |
overflow |
Capacity or numeric overflow. |
stopped |
Runtime or scheduler was stopped. |
queue_full |
Internal task queue is full. |
rejected |
Task submission was rejected. |
not_supported |
Operation is not supported on this platform. |
Creates a std::error_code from an async error.
std::error_code ec =
vix::async::core::make_error_code(
vix::async::core::errc::canceled);| Goal | API |
|---|---|
| Create runtime | vix::async::core::io_context ctx |
| Post callback | ctx.post(...) |
| Run scheduler | ctx.run() |
| Stop scheduler | ctx.stop() |
| Start task | std::move(task).start(ctx.get_scheduler()) |
| Sleep coroutine | ctx.timers().sleep_for(duration) |
| Delayed callback | ctx.timers().after(duration, fn) |
| Create cancellation source | cancel_source source |
| Get cancellation token | source.token() |
| Request cancellation | source.request_cancel() |
| Offload work | ctx.cpu_pool().submit(fn) |
| Wait all tasks | when_all(ctx.get_scheduler(), ...) |
| Wait first task | when_any(ctx.get_scheduler(), ...) |
| Wait signal | ctx.signals().async_wait() |
| Resolve DNS | resolver->async_resolve(host, port) |
| Connect TCP | stream->async_connect(endpoint) |
| Read TCP | stream->async_read(buffer) |
| Write TCP | stream->async_write(buffer) |
| Listen TCP | listener->async_listen(endpoint) |
| Accept TCP | listener->async_accept() |
| Bind UDP | socket->async_bind(endpoint) |
| Send UDP | socket->async_send_to(buffer, endpoint) |
| Receive UDP | socket->async_recv_from(buffer) |
#include <vix/async.hpp>
#include <vix/print.hpp>
int main()
{
vix::async::core::io_context ctx;
ctx.post([&ctx]()
{
vix::print("hello from async");
ctx.stop();
});
ctx.run();
return 0;
}#include <vix/async.hpp>
#include <vix/print.hpp>
#include <chrono>
using namespace std::chrono_literals;
vix::async::core::task<int> compute(
vix::async::core::io_context &ctx)
{
co_await ctx.timers().sleep_for(100ms);
co_return 42;
}
vix::async::core::task<void> app(
vix::async::core::io_context &ctx)
{
const int value = co_await compute(ctx);
vix::print("value =", value);
ctx.stop();
co_return;
}
int main()
{
vix::async::core::io_context ctx;
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
ctx.run();
return 0;
}#include <vix/async.hpp>
#include <vix/print.hpp>
#include <chrono>
#include <system_error>
using namespace std::chrono_literals;
vix::async::core::task<void> app(
vix::async::core::io_context &ctx)
{
vix::async::core::cancel_source source;
ctx.timers().after(100ms, [&source]()
{
source.request_cancel();
});
try
{
co_await ctx.timers().sleep_for(1s, source.token());
vix::print("sleep completed");
}
catch (const std::system_error &ex)
{
vix::eprint("cancelled:", ex.code().message());
}
ctx.stop();
co_return;
}
int main()
{
vix::async::core::io_context ctx;
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
ctx.run();
return 0;
}Wrong:
auto t = app(ctx);
ctx.run();Correct:
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
ctx.run();Wrong:
ctx.post([]()
{
vix::print("hello");
});Correct:
ctx.post([&ctx]()
{
vix::print("hello");
ctx.stop();
});
ctx.run();If nothing calls ctx.stop(), the context may continue waiting.
ctx.stop();Wrong:
std::this_thread::sleep_for(std::chrono::seconds(1));Correct:
co_await ctx.timers().sleep_for(std::chrono::seconds(1));For CPU-heavy work:
auto value = co_await ctx.cpu_pool().submit([]()
{
return expensive_work();
});Network write APIs expect byte spans.
Wrong:
co_await stream->async_write(message);Correct:
co_await stream->async_write(
std::as_bytes(std::span{message}));Network operations can throw.
try
{
co_await stream->async_connect(endpoint);
}
catch (const std::exception &ex)
{
vix::eprint(ex.what());
}Wrong:
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());
std::move(t).start(ctx.get_scheduler());Correct:
auto t = app(ctx);
std::move(t).start(ctx.get_scheduler());| Page | Purpose |
|---|---|
| Overview | Start with the async overview. |
| io_context | Learn the runtime context. |
| Tasks | Learn coroutine tasks. |
| Spawn | Learn how to start tasks. |
| Timers | Learn timer sleeps and callbacks. |
| Cancellation | Learn cooperative cancellation. |
| Thread pool | Learn background work. |
| when_all / when_any | Learn task composition. |
| Signals | Learn signal handling. |
| TCP | Learn TCP streams and listeners. |
| UDP | Learn UDP sockets. |
| DNS | Learn DNS resolution. |