鉴于以下测试计划:
#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).
但是,看起来好像包裹已打开内包装.
这是预期的行为吗?
事实证明这是我的误解.
这是Asio作者回复的副本:
嗨理查德,
是的,这种行为是故意的.但是,在网络TS和主分支上的最新代码中,此工具已从wrap(意味着向预期添加另一个层)重命名为bind_executor.该函数简单地用对象执行器填充对象; 如果它已经有一个它被覆盖.
如果你需要真正的包装,那么你应该将内部处理程序显式地包装在外部函数对象(或lambda)中,并将外部处理程序dispatch()作为其"关联执行器"的内部处理程序.当您编写自己的异步操作时,我建议采用以下模式(在网络TS中记录为"异步操作要求"的一部分):
使用get_associated_executor向处理程序询问其关联的执行程序.
post()如果你的操作立即完成,那个执行器的处理程序.
dispatch()否则执行者的处理程序.
所以(未经测试的代码,可能需要主分支的提示):
Run Code Online (Sandbox Code Playgroud)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(); }希望这可以帮助.
干杯,克里斯