Quick Start
Get a working Asio program running in five minutes.
| This guide requires C++20 with coroutine support. |
Minimal Example
Create a file timer.cpp:
#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using asio::awaitable;
using asio::use_awaitable;
awaitable<void> wait_one_second()
{
// Get the executor from the current coroutine
auto executor = co_await asio::this_coro::executor;
// Create a timer that expires in 1 second
asio::steady_timer timer(executor, std::chrono::seconds(1));
// Wait for the timer to expire
co_await timer.async_wait(use_awaitable);
std::cout << "Hello from Asio!\n";
}
int main()
{
// Create the I/O context — this runs the event loop
asio::io_context ctx;
// Spawn the coroutine onto the context
asio::co_spawn(ctx, wait_one_second(), asio::detached);
// Run the event loop until all work completes
ctx.run();
}
Build and Run
# Linux / macOS with GCC or Clang
g++ -std=c++20 -o timer timer.cpp -pthread
# Windows with MSVC
cl /std:c++20 /EHsc timer.cpp
# Run
./timer
Expected output after 1 second:
Hello from Asio!
What Just Happened?
-
io_context ctx— Created the event loop that drives all async operations -
co_spawn(ctx, wait_one_second(), detached)— Launched the coroutine on the context -
ctx.run()— Ran the event loop; blocks until all work completes -
Inside the coroutine:
-
co_await this_coro::executor— Got the executor from the coroutine’s context -
steady_timer timer(…)— Created a timer bound to that executor -
co_await timer.async_wait(use_awaitable)— Suspended until the timer expires
-
-
When the timer expired, the coroutine resumed and printed the message
-
The coroutine completed,
run()saw no more work, and returned
Key Concepts
|
The event loop. Manages I/O and runs completion handlers. |
|
Launches a coroutine onto an executor or context. |
|
A coroutine that returns |
|
Completion token that makes async operations return |
|
Completion token for |
Adding Error Handling
Asio coroutines report errors by throwing exceptions:
awaitable<void> connect_to_server()
{
try
{
auto executor = co_await asio::this_coro::executor;
asio::ip::tcp::socket socket(executor);
asio::ip::tcp::endpoint endpoint(
asio::ip::make_address("127.0.0.1"), 8080);
co_await socket.async_connect(endpoint, use_awaitable);
std::cout << "Connected!\n";
}
catch (const std::exception& e)
{
std::cerr << "Error: " << e.what() << "\n";
}
}
If you prefer error codes over exceptions, use as_tuple:
#include <boost/asio/experimental/as_tuple.hpp>
awaitable<void> connect_to_server()
{
auto executor = co_await asio::this_coro::executor;
asio::ip::tcp::socket socket(executor);
asio::ip::tcp::endpoint endpoint(
asio::ip::make_address("127.0.0.1"), 8080);
auto [ec] = co_await socket.async_connect(
endpoint,
asio::experimental::as_tuple(use_awaitable));
if (ec)
std::cerr << "Error: " << ec.message() << "\n";
else
std::cout << "Connected!\n";
}
Next Steps
Now that you have a working program:
-
Async Timer — More timer patterns
-
TCP Client — Network I/O with coroutines
-
The I/O Context — Understand the event loop