Инициирование асинхронной операции со стертым типомC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Инициирование асинхронной операции со стертым типом

Сообщение Anonymous »

Некоторое время назад я опубликовал этот вопрос и принял принятое решение, которое работает хорошо. Теперь мне нужна версия со стертым типом, чтобы я мог шаблонировать отправителя на основе типа сокета (т. е. шаблона class sender_impl;) для поддержки нескольких транспортов, но хранить их все в одном контейнере.
На основе этого примера я набросал следующее (полное раскрытие, я еще не пытался его скомпилировать), и я хочу убедиться, что я на правильном пути:

Код: Выделить всё

#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:
void 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, w = std::move(wrap)] mutable {
async_send_message_impl(buf, std::move(w));
});
}

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;
};
В частности, я вижу, что теперь вызываю asio::make_work_guard() иshared_from_this() внутри функции инициации, что, возможно, имеет последствия для времени жизни.
Я считаю, что это нормально с точки зрения времени жизни, если я предполагаю, что функция инициации вызывается до возврата async_initate(), но этот документ предполагает, что некоторые токены завершения могут выбрать отложить выполнение функции инициации, что предположительно может стать проблемой.
Несколько вопросов:
  • Правильный ли это подход?
  • Если нет, то что?
  • Откладывают ли какие-либо стандартные токены завершения (обратные вызовы, фьючерсы, ожидаемые объекты) функция инициации? Если нет, можете ли вы привести мне пример того, что могло бы быть? (РЕДАКТИРОВАТЬ: Глупый я, я думаю, отложенный является очевидным примером этого? Я наконец-то понимаю, что он делает сейчас...)


Подробнее здесь: https://stackoverflow.com/questions/798 ... initiation
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»