asio 1.11.0独立包装不正确......还是我?

Ric*_*ges 6 c++ boost-asio

鉴于以下测试计划:

#include <asio.hpp>
#include <cassert>

int main()
{
    asio::io_service ios1, ios2;
    asio::io_service::strand s2(ios2);

    auto test_func = wrap(s2, [&] {
        assert(s2.running_in_this_thread());
    });

    auto wrap_test_func = wrap(ios1, test_func);

    wrap_test_func();

    ios1.run_one();
    ios2.run_one();

}
Run Code Online (Sandbox Code Playgroud)

我的理解是这个程序不应断言.

wrap_test_func被包裹进去io_service ios1.它包装的功能被包装strand s2(使用ios2).

根据我的理解,调用wrap_test_func应该等于dispatch(ios1, test_func)哪个应该发送lambda in s2).

但是,看起来好像包裹已打开内包装.

这是预期的行为吗?

Ric*_*ges 5

事实证明这是我的误解.

这是Asio作者回复的副本:

嗨理查德,

是的,这种行为是故意的.但是,在网络TS和主分支上的最新代码中,此工具已从wrap(意味着向预期添加另一个层)重命名为bind_executor.该函数简单地用对象执行器填充对象; 如果它已经有一个它被覆盖.

如果你需要真正的包装,那么你应该将内部处理程序显式地包装在外部函数对象(或lambda)中,并将外部处理程序dispatch()作为其"关联执行器"的内部处理程序.当您编写自己的异步操作时,我建议采用以下模式(在网络TS中记录为"异步操作要求"的一部分):

  • 使用get_associated_executor向处理程序询问其关联的执行程序.

  • post()如果你的操作立即完成,那个执行器的处理程序.

  • dispatch()否则执行者的处理程序.

所以(未经测试的代码,可能需要主分支的提示):

    template<class Task, class Handler>
    void async_execute(implementation& impl, Task&& task, Handler&& handler)
    {
        ...

        auto ex = asio::get_associated_executor(handler get_io_context());

        // this is immediate completion, so we use post()

        if (not impl)
        {
            post(ex, [handler = std::forward<Handler>(handler)]() mutable
                 {
                     promise_type promise;
                     promise.set_exception(std::make_exception_ptr(system_error(errors::null_handle)));
                     handler(promise.get_future());
                 });
            return;
        }

        // this is not immediate completion, so we use dispatch()
        // (NOTE: assumes this->post_execute() does not run the task)

        // Optional. Really only needed if your io_context participates in the
        // async operation in some way not shown in this snippet, and not
        // simply as a channel for delivering the handler.
        auto io_work = make_work_guard(get_io_contet());

        auto handler_work = make_work_guard(ex);
        auto impl_ptr = impl.get();
        auto async_handler = [this,
                              ex,
                              impl_ptr,
                              io_work, handler_work,
                              handler = std::forward<Handler>(handler)]
        (detail::long_running_task_op::identifier ident,
         auto future) mutable
        {
            assert(impl_ptr);
            io_work.reset();
            dispatch(ex, [handler = std::move(handler), future = std::move(future)]() mutable
                 {
                     handler(std::move(future));
                 });
            assert(impl_ptr);
            impl_ptr->remove_op(ident);
        };

        ...

        this->post_execute();
    }
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

干杯,克里斯

  • @Arunmu不是从客户端用户的角度出发的.服务实现者(像我一样)有一些新技能需要学习,但是变化很好 - 特别是能够将只移动对象带入完成处理程序(例如期货),这就是我在这里所做的. (2认同)