mardi 19 février 2019

Is this a valid use of strands?

I'm trying to write an abstraction layer on top of asio and asio::thread_pool. I currently have two methods, read(..) and write(..) that use strands and async methods to send and receive data from a socket backed by an asio::thread_pool:

template <typename T>
auto abstract_connection<T>::write(std::vector<char> packet,
                                   std::function<void(std::error_code ec, std::size_t len)> cb) noexcept -> void {
  m_buffer = std::move(packet);
  asio::dispatch(m_strand, [&]() {
    asio::async_write(m_socket, asio::buffer(m_buffer),
                      [&, cb](std::error_code ec, std::size_t len) { cb(ec, len); });
  });
}

template <typename T>
auto abstract_connection<T>::read(std::function<void(std::error_code ec, std::vector<char> packet)> cb) noexcept -> void {
  m_buffer.clear();
  asio::dispatch(m_strand, [&, cb]() {
    asio::async_read(m_socket, asio::dynamic_buffer(m_buffer), asio::transfer_exactly(1),
                     [&, cb](std::error_code ec, std::size_t len) {
                       if (ec) {
                         cb(ec, std::move(m_buffer));
                       }
                       const auto available = m_socket.available();
                       asio::async_read(
                           m_socket, asio::dynamic_buffer(m_buffer), asio::transfer_exactly(available),
                           [&, cb](std::error_code ec, std::size_t len) { cb(ec, std::move(m_buffer)); });
                     });
  });
}

I understand that sequences of handlers should be wrapped within a strand to guarantee sequential execution, but is it safe to interleave calls to asio::dispatch within a thread pool, like this:

write(startup, [&](std::error_code e_code, std::size_t len) {
          if (e_code) {
            ec = e_code;
            return;
          }
          read([&](std::error_code ec, packet packet) { std::cerr << packet.size() << std::endl; });
        });

Aucun commentaire:

Enregistrer un commentaire