简体   繁体   中英

How to implement async/await syntax properly using Boost.Asio

I'm trying to implement some network application using Boost.Asio. I have a problem with multiple layers of callbacks. In other languages that natively support async/await syntax, I can write my logic like this

void do_send(args...) {
  if (!endpoint_resolved) {
    await resolve_async(...);  // results are stored in member variables
  }
  if (!connected) {
    await connect_async(...);
  }
  await send_async(...);
  await receive_async(...);
}

Right now I have to write it using multiple layers of callbacks

void do_send(args...) {
  if (!endpoint_resolved) {
    resolve_async(..., [captures...](args...) {
      if (!connected) {
        connect_async(..., [captures...](args...) {
          send_async(..., [captures...](args...) {
            receive_async(..., [captures...](args...) {
              // do something
            });  // receive_async
          });  // send_async
        });  // connect_async
      }
    });
  }
}

This is cumbersome and error-prone. An alternative is to use std::bind to bind member functions as callbacks, but this does not solve the problem because either way I have to write complicated logic in the callbacks to determine what to do next.

I'm wondering if there are better solutions. Ideally I would like to write code in a synchronous way while I can await asynchronously on any I/O operations.

I've also checked std::async , std::future , etc. But they don't seem to fit into my situation.

Boost.Asio's stackful coroutines would provide a good solution. Stackful coroutines allow for asynchronous code to be written in a manner that reads synchronous. One can create a stackful coroutine via the spawn function. Within the coroutine, passing the yield_context as a handler to an asyncornous operation will start the operation and suspend the coroutine. The coroutine will be resumed automatically when the asynchronous operation completes. Here is the example from the documentation:

boost::asio::spawn(my_strand, do_echo);

// ...

void do_echo(boost::asio::yield_context yield)
{
  try
  {
    char data[128];
    for (;;)
    {
      std::size_t length =
        my_socket.async_read_some(
          boost::asio::buffer(data), yield);

      boost::asio::async_write(my_socket,
          boost::asio::buffer(data, length), yield);
    }
  }
  catch (std::exception& e)
  {
    // ...
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM