Getting Started¶
This page walks through building coio, integrating it into a CMake project, and writing a first program.
Requirements¶
- A C++20/C++23 compatible compiler (recent GCC, Clang, or MSVC).
- CMake 3.30+.
- Platform backends:
- Linux:
epoll_contextworks on any modern kernel;uring_contextadditionally needs liburing and a 5.19+ kernel at runtime (probed at context construction). - Windows:
iocp_contextuses I/O Completion Ports.
- Linux:
- A
std::executionimplementation (fetched automatically depending on the selected backend, see below).
Building¶
Build options¶
| Option | Default | Description |
|---|---|---|
COIO_BUILD_EXAMPLES |
OFF |
Build the example programs under examples/ |
COIO_BUILD_TESTS |
OFF |
Build the doctest-based tests |
COIO_BUILD_WITH_ASAN |
OFF |
Enable AddressSanitizer |
COIO_BUILD_WITH_TSAN |
OFF |
Enable ThreadSanitizer |
COIO_BUILD_WITH_UBSAN |
OFF |
Enable UndefinedBehaviorSanitizer |
COIO_SENDERS_BACKEND |
NVIDIA |
Which std::execution implementation to use (see below) |
Choosing a std::execution backend¶
coio programs against standard std::execution; the concrete implementation is selected at configure time with COIO_SENDERS_BACKEND:
| Value | Implementation |
|---|---|
NVIDIA |
NVIDIA/stdexec (default) |
BEMAN |
bemanproject/execution |
CXX26 |
The standard library's own <execution> (requires a C++26 standard library that ships P2300) |
The choice is propagated to consumers through the COIO_EXECUTION_USE_* public compile definition, so no source changes are needed when switching.
Using coio from your project¶
Add coio as a subdirectory (or via CPM / FetchContent) and link the target:
add_subdirectory(coio) # or CPMAddPackage / FetchContent
target_link_libraries(app PRIVATE coio::coio)
install() rules are provided, so a packaged build with find_package(coio) also works.
A first program¶
#include <coio/core.h>
#include <coio/execution_context.h>
#include <coio/utils/timer.h>
#include <iostream>
using namespace std::chrono_literals;
auto greet(coio::time_loop::scheduler sched) -> coio::task<> {
coio::timer timer{sched};
co_await timer.async_wait(1s);
std::cout << "hello, coio!\n";
}
auto main() -> int {
coio::time_loop context;
coio::this_thread::sync_wait(coio::when_all(
greet(context.get_scheduler()),
[&context]() -> coio::task<> { context.run(); co_return; }()
));
}
What happens here:
coio::time_loopis a portable execution context with a timer queue.greetis atask— a lazily-started coroutine that is also a sender.co_await timer.async_wait(1s)suspends the coroutine; the timer completes on the context's consumer thread.context.run()drives the loop until no work remains;sync_waitblocksmainuntil everything finishes.
Choosing an execution context¶
| Context | Platform | Use it for |
|---|---|---|
time_loop |
portable | scheduling, timers, CPU-bound task orchestration |
epoll_context |
Linux | sockets and pipes via readiness-based I/O |
uring_context |
Linux (kernel 5.19+) | sockets, pipes and files via io_uring |
iocp_context |
Windows | sockets, pipes and files via IOCP |
All contexts share the same driving API (run/poll family) and threading contract — see Execution Contexts.