Viktor Khristenko
Viktor Khristenko

Reputation: 933

boost asio cancellation signal

code snippet:

template<typename CompletionToken>
boost::awaitable<int> async_op(CompletionToken) {...}

boost::asio::cancellation_signal cancel_signal;
...
auto value = co_await async_op(boost::asio::bind_cancellation_slot(
    cancel_token.slot(),
    boost::asio::use_awaitable));
...

// use signal
cancel_signal.emit(boost::asio::cancellation_type::total);

I have 2 questions

  1. is that correct/most basic pattern of how to cancel a coroutine. those that support of course.
  2. Are there other ways to perform the same. In particular, what if one does not have access to the exact signal.

thanks

Upvotes: 1

Views: 1160

Answers (1)

Bernd36
Bernd36

Reputation: 163

I think the most basic pattern is to use the (experimental) awaitable operators, like so:

#include <boost/asio.hpp>
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <iostream>
#include <thread>

namespace io = boost::asio;
using namespace boost::asio::experimental::awaitable_operators;
using namespace std::chrono_literals;

io::awaitable<void> Cancelled(io::steady_timer& cancelTimer)
{
    boost::system::error_code ec;
    co_await cancelTimer.async_wait(io::redirect_error(io::use_awaitable, ec));
}

io::awaitable<void> AsyncOp(io::io_context& context)
{
    io::steady_timer timer{ context, 100ms };
    co_await timer.async_wait(io::use_awaitable);
}

io::awaitable<void> Run(io::io_context& context, io::steady_timer& cancelTimer)
{
    const auto result { co_await(AsyncOp(context) || Cancelled(cancelTimer)) };
    if (result.index() == 0)
        std::cout << "AsyncOp completed" << std::endl;
    else
        std::cout << "AsyncOp cancelled" << std::endl;
}

int main()
{
    try
    {
        io::io_context context;
        io::steady_timer cancelTimer{ context, 
              std::chrono::steady_clock::duration::max() };

        io::co_spawn(context, Run(context, cancelTimer), io::detached);

        std::future<void> contextRun{ std::async([&context] { context.run(); }) };

        std::this_thread::sleep_for(10ms);
        cancelTimer.cancel();

        contextRun.get();
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

I highly recommend watching Talk Async.

Upvotes: 1

Related Questions