asio use_future вместо yield[ec]

я хочу сделать контейнер фьючерсов, каждое будущее является пустым результатом задачи, чтобы я мог использовать wait_for_any в контейнере, каждая задача - это сопрограмма, которую я в настоящее время реализую с использованием yield_context, и внутри этой сопрограммы есть инициирующая функция, которая возвращает ec и результат, где я использую ec для анализа результата. а затем вызывается другая сопрограмма, которая передает тот же yield_context.
я хочу знать, как сделать этот дизайн.
и если я буду использовать use_future, как я могу передать код ошибки в ec, не бросая это, если нет другого способа, кроме как бросить его, в этом случае я попробую и поймаю асинхронные инициирующие функции.
все эти задачи будут опубликованы, порождены ... на asio io_service.
это мои основные части кода:
это порождение задачи

boost::asio::spawn(GetServiceReference(), boost::bind(&HTTPRequest::Execute, boost::placeholders::_1, m_HttpClient_request_name, Get_mHTTPClient_Responses_Map()));

и это сопрограмма, использующая yield_context

void HTTPRequest::Execute(boost::asio::yield_context yield_r, std::string request_name, std::map<std::string, boost::shared_ptr<HTTPResponse>>& mHTTPClient_Responses_Map)
{
    resolver_iterator iterator_connect = boost::asio::async_connect(mSock, iterator_resolve, yield_r[ec]);
}

а внутри Execute мы используем ec для анализа

if (ec == boost::system::errc::errc_t::success){}

и здесь мы запускаем другую сопрограмму, передающую тот же yield_context

SendRequest(yield_r);
}

я хочу изменить это, чтобы у меня был контейнер фьючерсов для всех порожденных Execute, меня не волнуют результаты Execute, потому что я помещаю их в ответ класса-члена.
Но мне нужен результат в будущем, чтобы я мог использовать wait_any на контейнер .


person ahmed allam    schedule 04.04.2020    source источник


Ответы (1)


Если вы можете изменить свою реализацию, используйте шаблон async_result.

Это делает так, что вы можете использовать свой метод с любым из подходов (обработчик завершения, контекст доходности или use_future).

Я воспроизвожу автономный пример из здесь для вдохновения:

Полная демонстрация

Показывая, как использовать его с with

  • coro и доходность [ec]
  • coro и yield + исключения
  • станд::будущее
  • обработчики завершения

Прямой эфир на Coliru

#define BOOST_COROUTINES_NO_DEPRECATION_WARNING 
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/use_future.hpp>

using boost::system::error_code;
namespace asio = boost::asio;

template <typename Token>
auto async_meaning_of_life(bool success, Token&& token)
{
#if BOOST_VERSION >= 106600
    using result_type = typename asio::async_result<std::decay_t<Token>, void(error_code, int)>;
    typename result_type::completion_handler_type handler(std::forward<Token>(token));

    result_type result(handler);
#else
    typename asio::handler_type<Token, void(error_code, int)>::type
                 handler(std::forward<Token>(token));

    asio::async_result<decltype (handler)> result (handler);
#endif

    if (success)
        handler(error_code{}, 42);
    else
        handler(asio::error::operation_aborted, 0);

    return result.get ();
}

void using_yield_ec(asio::yield_context yield) {
    for (bool success : { true, false }) {
        boost::system::error_code ec;
        auto answer = async_meaning_of_life(success, yield[ec]);
        std::cout << __FUNCTION__ << ": Result: " << ec.message() << "\n";
        std::cout << __FUNCTION__ << ": Answer: " << answer << "\n";
    }
}

void using_yield_catch(asio::yield_context yield) {
    for (bool success : { true, false }) 
    try {
        auto answer = async_meaning_of_life(success, yield);
        std::cout << __FUNCTION__ << ": Answer: " << answer << "\n";
    } catch(boost::system::system_error const& e) {
        std::cout << __FUNCTION__ << ": Caught: " << e.code().message() << "\n";
    }
}

void using_future() {
    for (bool success : { true, false }) 
    try {
        auto answer = async_meaning_of_life(success, asio::use_future);
        std::cout << __FUNCTION__ << ": Answer: " << answer.get() << "\n";
    } catch(boost::system::system_error const& e) {
        std::cout << __FUNCTION__ << ": Caught: " << e.code().message() << "\n";
    }
}

void using_handler() {
    for (bool success : { true, false })
        async_meaning_of_life(success, [](error_code ec, int answer) {
            std::cout << "using_handler: Result: " << ec.message() << "\n";
            std::cout << "using_handler: Answer: " << answer << "\n";
        });
}

int main() {
    asio::io_service svc;

    spawn(svc, using_yield_ec);
    spawn(svc, using_yield_catch);
    std::thread work([] {
            using_future();
            using_handler();
        });

    svc.run();
    work.join();
}

Отпечатки:

using_yield_ec: Result: Success
using_yield_ec: Answer: 42
using_yield_ec: Result: Operation canceled
using_yield_ec: Answer: 0
using_future: Answer: 42
using_yield_catch: Answer: 42
using_yield_catch: Caught: Operation canceled
using_future: Caught: Operation canceled
using_handler: Result: Success
using_handler: Answer: 42
using_handler: Result: Operation canceled
using_handler: Answer: 0

Примечание: для простоты я не добавлял синхронизацию вывода, поэтому вывод может смешиваться в зависимости от порядка выполнения во время выполнения.

person sehe    schedule 05.04.2020
comment
я изучил ваш ответ во время поиска, и он уже добавлен в закладки, но мне трудно понять, что на самом деле происходит, когда токен завершения преобразуется в обработчик. Во всех примерах говорится об использовании подписи для формирования типа обработчика. но сформированный обработчик - это просто прототип. нет тела для обработчика. Итак, что будет вызываться, когда асинхронная операция завершится????. Что касается моего текущего вопроса, я все еще не понимаю порядок операций. Например: я создам упакованные задачи, а затем добавлю их в контейнер. ..НО запускать ios.run из того же потока или из другого? - person ahmed allam; 05.04.2020
comment
завершающий комментарий: и где я должен вызывать: wait_for_any??? в том же потоке, где я делал задачи, ИЛИ после ios.run в том же или другом потоке??? - person ahmed allam; 05.04.2020
comment
теперь я думаю, что понял, что означает обработчик ... это просто определение типа. и есть несколько случаев, я думаю, что они называются признаками типа, которые определяют во время компиляции, какой тип передается обработчику, и в соответствии с этим они передают аргументы подпись к определенному типу или части аргументов, например, в случае будущего ... Так что будет вызываться аргумент, переданный от пользователя, если это функция objectlambda, bind, callback, указатель функции или это будущий механизм создания в случае use_future , либо это просто переключение контекстов в случае стейкинговых сопрограмм, либо это безстейкинговый ››› - person ahmed allam; 17.04.2020
comment
сопрограмма на случай, если передано перемещение (coro). Я правильно? Теперь, как мы можем использовать эти различные токены завершения с spawn, post??? Можем ли мы избежать создания async_function и использовать packaged_task для преобразования функции в задачу, возвращающую будущее? ??Результирующая задача такая же, как и async_function??Будем ли мы использовать async_function с упакованной задачей ИЛИ using_future?? - person ahmed allam; 17.04.2020
comment
Я проголосовал за комментарий, который, я думаю, я понял и имеет большой смысл. Я не знаю, что вы имеете в виду со всеми вопросами (???) - person sehe; 18.04.2020
comment
когда я пытаюсь использовать функции в своем коде, у меня есть 2 варианта, насколько я знаю, на данный момент: во-первых, избегать создания составной функции напрямую и попытаться использовать packaged_task, чтобы сделать задачу из моей функции, а затем опубликовать эту задачу ›› › это приводит к некоторым ошибкам, которые остановили мой прогресс, и я сделал stackoverflow.com/questions/61181774/, чтобы обратиться за помощью по этому поводу. ИЛИ второй вариант — прочитать о составной функции и универсальной модели, которая очень интересна, но более сложна и это имел несколько потребностей в знании таких предметов, как черты шрифта и - person ahmed allam; 18.04.2020
comment
идеальная переадресация, которая приводит к универсальным ссылкам, SFINAE, псевдонимам шаблонов и макросам, которые так интересны, и я рад, что прочитал их, всегда старался избегать этих сложных тем. Итак, теперь я пытаюсь сделать составную функцию, но удивляюсь, почему у меня была ошибка с моим первым подходом, использующим packaged_task с post. Итак, я догадался, что spawn просто используется с составной операцией с использованием yield в качестве токена завершения? это правильно? ... и packaged_task просто используется с потоками и не может использоваться с post, который требует копирования задача и задача только для перемещения,??это правильно?? - person ahmed allam; 18.04.2020
comment
и во время этого я столкнулся с вопросом: преобразована ли функция в задачу с использованием упакованной задачи, ЭКВИВАЛЕНТНА ли асинхронно составленной функции с использованием use_future?? спасибо за ваш ответ - person ahmed allam; 18.04.2020
comment
я сделал несколько дополнений к вашему примеру кода, чтобы попытаться понять асинхронную составную функцию. t.async_wait(&print); автоответ = async_meaning_of_life(true, asio::use_future); std::cout ‹‹ ФУНКЦИЯ ‹‹ : Ответ: ‹‹ answer.get() ‹‹ \n; - person ahmed allam; 18.04.2020
comment
Можете ли вы опубликовать новый вопрос? В общем, packaged_task не эквивалентен, главным образом потому, что он стирает фактический тип обработчика. Типы обработчиков включают информацию, например, когда используется цепь. Стирая тип с помощью packaged_task, ASIO теряет фактический тип обработчика и не может поддерживать семантику. - person sehe; 18.04.2020
comment
Я задал этот вопрос 5 дней назад. stackoverflow .com/questions/61181774/. это в основном о моей первоначальной проблеме. но я обнаружил, что у меня недостаточное понимание нескольких основных вещей, которые я пытаюсь получить. я пробую несколько разных случаев с вашим кодом. я опубликую их после завершения. я приму ваш ответ сейчас и продолжить его модификации в следующем вопросе - person ahmed allam; 18.04.2020
comment
и это еще один вопрос с изменениями в вашем коде, чтобы показать мои неясные моменты и мои вопросы заголовок stackoverflow.com/questions/61329157/ - person ahmed allam; 20.04.2020