-
Notifications
You must be signed in to change notification settings - Fork 0
Core Concepts
This page explains the fundamental concepts behind Elio's design.
Elio uses C++23 coroutines as the foundation for async programming. A coroutine is a function that can suspend and resume execution.
coro::task<T> is the primary coroutine type in Elio:
#include <elio/coro/task.hpp>
// A task that returns an int
coro::task<int> compute() {
co_return 42;
}
// A task that returns nothing
coro::task<void> do_work() {
int result = co_await compute();
ELIO_LOG_INFO("Result: {}", result);
co_return;
}Use co_await to wait for a task to complete:
coro::task<void> example() {
// Sequential execution
int a = co_await compute();
int b = co_await compute();
ELIO_LOG_INFO("Sum: {}", a + b);
co_return;
}The scheduler manages coroutine execution across multiple threads.
#include <elio/runtime/scheduler.hpp>
// Create with N worker threads
runtime::scheduler sched(4);
// Start the scheduler
sched.start();
// Spawn tasks
auto task = my_coroutine();
sched.spawn(task.release());
// Shutdown when done
sched.shutdown();Elio uses a work-stealing scheduler for load balancing. Each worker thread has a local queue, and idle workers steal tasks from busy workers.
The I/O context manages async I/O operations.
#include <elio/io/io_context.hpp>
// Get the global I/O context
auto& ctx = io::default_io_context();
// Associate with scheduler
sched.set_io_context(&ctx);Elio supports two I/O backends:
| Backend | Kernel Version | Performance |
|---|---|---|
| io_uring | Linux 5.1+ | Best |
| epoll | Any Linux | Good |
The backend is selected automatically at compile time based on availability.
Awaitables are types that can be used with co_await. Elio provides several built-in awaitables:
// Read from a socket
auto result = co_await stream.read(buffer, size);
// Write to a socket
auto result = co_await stream.write(data, len);
// Accept a connection
auto stream = co_await listener.accept();#include <elio/time/timer.hpp>
// Sleep for a duration
co_await time::sleep(io_ctx, std::chrono::seconds(1));
// Sleep until a time point
co_await time::sleep_until(io_ctx, deadline);Elio provides coroutine-aware synchronization primitives.
#include <elio/sync/primitives.hpp>
sync::mutex mtx;
coro::task<void> critical_section() {
auto lock = co_await mtx.lock();
// Protected code here
co_return;
}sync::condition_variable cv;
sync::mutex mtx;
bool ready = false;
coro::task<void> waiter() {
auto lock = co_await mtx.lock();
co_await cv.wait(lock, [&] { return ready; });
// Condition met
co_return;
}
coro::task<void> notifier() {
{
auto lock = co_await mtx.lock();
ready = true;
}
cv.notify_one();
co_return;
}sync::semaphore sem(10); // Max 10 concurrent
coro::task<void> limited_work() {
co_await sem.acquire();
// Do work
sem.release();
co_return;
}Elio uses std::expected for error handling in I/O operations:
coro::task<void> handle_errors() {
auto result = co_await stream.read(buffer, size);
if (result.result > 0) {
// Success - result.result contains bytes read
} else if (result.result == 0) {
// EOF - connection closed
} else {
// Error - result.result is negative errno
ELIO_LOG_ERROR("Read error: {}", strerror(-result.result));
}
co_return;
}Elio includes a built-in logging system:
#include <elio/log/macros.hpp>
ELIO_LOG_DEBUG("Debug message");
ELIO_LOG_INFO("Info: value={}", 42);
ELIO_LOG_WARNING("Warning!");
ELIO_LOG_ERROR("Error: {}", strerror(errno));
// Set log level
log::logger::instance().set_level(log::level::debug);- Learn about Networking for TCP and HTTP
- See Examples for complete code samples