Boost
C++ Libraries
...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
This version of Boost is under active development. You are currently in the master branch. The current version is 1.91.0.
In the previous tutorial we used synchronous functions. They are simple, but have a number of limitations:
connection_pool)
only offer an async interface.
For this reason, we recommend to always use async functions. All Asio-compatible libraries (including this one) allow async programming using a variety of styles. In this chapter, we will explain how to use C++20 coroutines because they are the simplest to use.
![]() |
Note |
|---|---|
Still not using C++20? Don't worry, you can use stackful coroutines and callbacks even in C++11. |
Roughly speaking, it's a function that can suspend and resume, keeping local
variables alive in the process. Suspension happens when reaching a co_await expression. These usually appear
when the program performs an I/O operation. When an expression like this is
encountered, the following happens:
io_context
(that is, the event loop).
io_context
may run other operations, like other coroutines.
io_context
resumes the coroutine immediately after the co_await
expression.
Recall the following code from our previous tutorial:
// The hostname, username and password to use mysql::connect_params params; params.server_address.emplace_host_and_port(hostname); params.username = username; params.password = password; // Connect to the server conn.connect(params); // Issue the SQL query to the server const char* sql = "SELECT 'Hello world!'"; mysql::results result; conn.execute(sql, result); // Print the first field in the first row std::cout << result.rows().at(0).at(0) << std::endl; // Close the connection conn.close();
To transform this code into a coroutine, we need to:
boost::asio::awaitable<void>.
any_connection::connect)
by async ones (like any_connection::async_connect).
co_await operator
in front of each I/O operation.
Doing this, we have:
asio::awaitable<void> coro_main( mysql::any_connection& conn, std::string_view server_hostname, std::string_view username, std::string_view password ) { // The hostname, username, password and database to use. // TLS is used by default. mysql::connect_params params; params.server_address.emplace_host_and_port(std::string(server_hostname)); params.username = username; params.password = password; // Connect to the server co_await conn.async_connect(params); // Issue the SQL query to the server const char* sql = "SELECT 'Hello world!'"; mysql::results result; co_await conn.async_execute(sql, result); // Print the first field in the first row std::cout << result.rows().at(0).at(0) << std::endl; // Close the connection co_await conn.async_close(); }
Note that the coroutine doesn't create or return explicitly any boost::asio::awaitable<void>
object - this is handled by the compiler. The return type actually marks the
function as being a coroutine. void
here means that the coroutine doesn't return anything.
If any of the above I/O operations fail, an exception is thrown. You can prevent
this by using asio::redirect_error.
As in the previous tutorial, we first need to create an io_context
and a connection:
// The execution context, required to run I/O operations. asio::io_context ctx; // Represents a connection to the MySQL server. mysql::any_connection conn(ctx);
To run a coroutine, use asio::co_spawn:
// Enqueue the coroutine for execution. // This does not wait for the coroutine to finish. asio::co_spawn( // The execution context where the coroutine will run ctx, // The coroutine to run. This must be a function taking no arguments // and returning an asio::awaitable<T> [&conn, argv] { return coro_main(conn, argv[3], argv[1], argv[2]); }, // Callback to run when the coroutine completes. // If any exception is thrown in the coroutine body, propagate it to terminate the program. [](std::exception_ptr ptr) { if (ptr) { std::rethrow_exception(ptr); } } );
Note that this will only schedule the coroutine. To actually run it, we need
to call io_context::run. This will block the calling thread until
all the scheduled coroutines and I/O operations complete:
// Calling run will actually execute the coroutine until completion ctx.run();
Full program listing for this tutorial is here.
You can now proceed to the next tutorial.