鉴于以下测试计划:
#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。
然而,看起来好像包装已经展开了内包装。
这是预期的行为吗?
答案 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(); }
希望这有帮助。
干杯,克里斯