На основе этого примера я набросал следующее (полное раскрытие, я еще не пытался его скомпилировать), и я хочу убедиться, что я на правильном пути:
Код: Выделить всё
#include "asio/buffer.hpp"
#include
#include
#include
namespace asio = boost::asio;
using tcp = asio::ip::tcp;
using boost::system::error_code;
class sender
{
public:
virtual ~sender() = default;
template auto async_send_message(asio::const_buffer buf, Token&& token) {
auto init = [this](auto handler, asio::const_buffer buf) {
do_async_send_message(buf, std::move(handler));
};
return asio::async_initiate(init, std::forward(token), buf);
}
private:
virtual void do_async_send_message(asio::const_buffer buf, asio::any_completion_handler h) = 0;
};
class sender_impl : public sender, public std::enable_shared_from_this {
public:
explicit sender_impl(tcp::socket sock) : _socket(std::move(sock)) {}
private:
template auto do_async_send_message(asio::const_buffer buf, asio::any_completion_handler h) final {
auto wrap = asio::consign(std::move(h), asio::make_work_guard(_socket.get_executor()));
// Initiate the async operation on the socket's strand
asio::dispatch(_socket.get_executor(), //
[this, me = shared_from_this(), buf, h = std::move(h)] mutable {
async_send_message_impl(buf, std::move(h));
});
}
template void async_send_message_impl(asio::const_buffer buf, Handler h) {
_send_queue.emplace_back(buf, std::move(h));
// Queue was empty meaning there's no active send loop, so start one.
if (_send_queue.size() == 1)
send_loop();
}
void send_loop() {
if (_send_queue.empty())
return;
asio::async_write( //
_socket, _send_queue.front().first, [this, me = shared_from_this()](error_code ec, std::size_t) {
auto& h = _send_queue.front().second;
auto const& ex = asio::get_associated_executor(h, _socket.get_executor());
asio::dispatch(ex, [h = std::move(h), ec]() mutable { h(ec); });
if (!ec.failed()) {
// Keep sending until no messages left to send.
_send_queue.pop_front();
send_loop();
}
});
}
using entry = std::pair;
tcp::socket _socket;
std::deque _send_queue;
};
Я считаю, что это нормально с точки зрения времени жизни, если я предполагаю, что функция инициации вызывается до возврата async_initate(), но этот документ предполагает, что некоторые токены завершения могут выбрать отложить выполнение функции инициации, что предположительно может стать проблемой.
Несколько вопросов:
- Правильный ли это подход?
- Если нет, то что?
- Откладывают ли какие-либо стандартные токены завершения (обратные вызовы, фьючерсы, ожидаемые объекты) функция инициации? Если нет, можете ли вы привести мне пример того, что могло бы быть? (РЕДАКТИРОВАТЬ: Глупый я, я думаю, отложенный является очевидным примером этого? Я наконец-то понимаю, что он делает сейчас...)
Подробнее здесь: https://stackoverflow.com/questions/798 ... initiation