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

时间:2016-08-10 18:11:29

标签: 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();

}

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

wrap_test_func已包含在io_service ios1中。它包装的功能包含在strand s2中(使用ios2)。

据我了解,调用wrap_test_func应该等同于dispatch(ios1, test_func),然后应该在s2中调度lambda。

然而,看起来好像包装已经展开了内包装。

这是预期的行为吗?

1 个答案:

答案 0 :(得分:5)

原来这是我的误解。

以下是Asio作者的回复副本:

  

嗨理查德,

     

是的,这种行为是故意的。但是,在网络TS和   主分支上的最新代码此工具已重命名   来自wrap(暗示如你所期望的那样添加另一个层)   bind_executor。这个函数简单地用一个对象填充对象   相关执行人;如果它已经有一个它被覆盖。

     

如果你需要真正的包装,那么你应该明确地包裹你的内心   处理器在外部函数对象(或lambda)中,并具有外部   handler dispatch()其“关联执行器”上的内部处理程序。如   你正在编写自己的异步操作,我建议采用   以下模式(作为网络TS的一部分记录在网络TS中)   “对异步操作的要求”):

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

  •   
  • 如果您的操作立即完成,则将该处理程序发送给该执行程序。

  •   
  • 以其他方式将处理程序发送给该执行程序。

  •   
     

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

    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();
    }
     

希望这有帮助。

     

干杯,克里斯