N.B. The Windows-specific tick_count_timer example has been removed as
it has been superseded by timers based on the standard steady_clock.
It's also not clear how to map a wrapping time source to the standard
chrono concepts.
Define BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM to enable the
old Boost.Date_Time interface in basic_socket_streambuf and
basic_socket_iostream.
* Use asio::steady_timer rather than asio::deadline_timer.
* Use asio::dynamic_buffer rather than asio::streambuf.
* Use timed asio::io_context::run_for() function for blocking clients.
* Add example showing a custom completion token for blocking with timeouts.
for returning a C++11 std::future from an asynchronous operation's
initiating function.
To use asio::use_future, pass it to an asynchronous operation instead of
a normal completion handler. For example:
std::future<std::size_t> length =
my_socket.async_read_some(my_buffer, asio::use_future);
Where a completion handler signature has the form:
void handler(error_code ec, result_type result);
the initiating function returns a std::future templated on result_type.
In the above example, this is std::size_t. If the asynchronous operation
fails, the error_code is converted into a system_error exception and
passed back to the caller through the future.
Where a completion handler signature has the form:
void handler(error_code ec);
the initiating function returns std::future<void>. As above, an error
is passed back in the future as a system_error exception.
[SVN r84313]
stackful coroutines. It is based on the Boost.Coroutine library.
Here is an example of its use:
asio::spawn(my_strand, do_echo);
// ...
void do_echo(asio::yield_context yield)
{
try
{
char data[128];
for (;;)
{
std::size_t length =
my_socket.async_read_some(
asio::buffer(data), yield);
asio::async_write(my_socket,
asio::buffer(data, length), yield);
}
}
catch (std::exception& e)
{
// ...
}
}
The first argument to asio::spawn() may be a strand, io_service or
completion handler. This argument determines the context in which the
coroutine is permitted to execute. For example, a server's per-client
object may consist of multiple coroutines; they should all run on the
same strand so that no explicit synchronisation is required.
The second argument is a function object with signature (**):
void coroutine(asio::yield_context yield);
that specifies the code to be run as part of the coroutine. The
parameter yield may be passed to an asynchronous operation in place of
the completion handler, as in:
std::size_t length =
my_socket.async_read_some(
asio::buffer(data), yield);
This starts the asynchronous operation and suspends the coroutine. The
coroutine will be resumed automatically when the asynchronous operation
completes.
Where a completion handler signature has the form:
void handler(error_code ec, result_type result);
the initiating function returns the result_type. In the async_read_some
example above, this is std::size_t. If the asynchronous operation fails,
the error_code is converted into a system_error exception and thrown.
Where a completion handler signature has the form:
void handler(error_code ec);
the initiating function returns void. As above, an error is passed back
to the coroutine as a system_error exception.
To collect the error_code from an operation, rather than have it throw
an exception, associate the output variable with the yield_context as
follows:
error_code ec;
std::size_t length =
my_socket.async_read_some(
asio::buffer(data), yield[ec]);
**Note: if asio::spawn() is used with a custom completion handler of
type Handler, the function object signature is actually:
void coroutine(asio::basic_yield_context<Handler> yield);
[SVN r84311]